Vodič za NanoHTTPD

1. Uvod

NanoHTTPD je otvoreni, lagani web poslužitelj napisan na Javi.

U ovom uputstvu stvorit ćemo nekoliko REST API-ja kako bismo istražili njegove značajke.

2. Postavljanje projekta

Dodajmo ovisnost jezgre NanoHTTPD u našu pom.xml:

 org.nanohttpd nanohttpd 2.3.1 

Da bismo stvorili jednostavan poslužitelj, moramo ga proširiti NanoHTTPD i nadjačati svoje poslužiti metoda:

aplikacija javne klase proširuje NanoHTTPD {javna aplikacija () baca IOException {super (8080); start (NanoHTTPD.SOCKET_READ_TIMEOUT, netačno); } public static void main (String [] args) baca IOException {new App (); } @Override public Response serve (IHTTPSession session) {return newFixedLengthResponse ("Hello world"); }}

Svoju izvodnu luku definirali smo kao 8080 i poslužitelj za rad kao demon (bez vremenskog ograničenja čitanja).

Nakon što pokrenemo aplikaciju, URL // localhost: 8080 / vratit će Pozdrav svijete poruka. Koristimo NanoHTTPD # newFixedLengthResponse metoda kao prikladan način izgradnje a NanoHTTPD.Odgovor objekt.

Pokušajmo s cURL-om:

> curl '// localhost: 8080 /' Pozdrav svijete

3. REST API

Na način HTTP metoda, NanoHTTPD omogućuje GET, POST, PUT, DELETE, HEAD, TRACE i nekoliko drugih.

Jednostavno rečeno, podržane HTTP glagole možemo pronaći putem metode enum. Da vidimo kako će se ovo odigrati.

3.1. HTTP GET

Prvo, pogledajmo GET. Recimo, na primjer, da želimo vratiti sadržaj samo kada aplikacija primi GET zahtjev.

Za razliku od Java Servlet spremnika, mi nemamo doGet dostupna metoda - umjesto toga, samo provjeravamo vrijednost putem getMethod:

@Override public Response serve (IHTTPSession session) {if (session.getMethod () == Method.GET) {String itemIdRequestParameter = session.getParameters (). Get ("itemId"). Get (0); return newFixedLengthResponse ("Zatraženi itemId =" + itemIdRequestParameter); } return newFixedLengthResponse (Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Zatraženi resurs ne postoji"); }

To je bilo prilično jednostavno, zar ne? Izvršimo brzi test uvijanjem nove krajnje točke i vidjet ćemo parametar zahtjeva itemId se pravilno čita:

> curl '// localhost: 8080 /? itemId = 23Bk8' Traženi itemId = 23Bk8

3.2. HTTP POST

Prethodno smo reagirali na GET i pročitali parametar iz URL-a.

Da bismo pokrili dvije najpopularnije HTTP metode, vrijeme je da obradimo POST (i tako čitamo tijelo zahtjeva):

@Preuzmi javni odgovor na odgovore (IHTTPSession session) {if (session.getMethod () == Method.POST) {try {session.parseBody (new HashMap ()); String requestBody = session.getQueryParameterString (); return newFixedLengthResponse ("Tijelo zahtjeva =" + requestBody); } catch (IOException | ResponseException e) {// handle}} return newFixedLengthResponse (Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Zatraženi resurs ne postoji"); }
Primijetite da smo prije nego što smo zatražili tijelo zahtjeva, prvo smo nazvali raščlaniti tijelo metoda. To je zato što smo željeli učitati tijelo zahtjeva za kasnije preuzimanje.

Uključit ćemo tijelo u naš kovrča naredba:

> curl -X POST -d 'deliveryAddress = Washington nr 4 & quantity = 5' '// localhost: 8080 /' Tijelo zahtjeva = deliveryAddress = Washington nr 4 & quantity = 5

Preostale HTTP metode vrlo su slične po svojoj prirodi, pa ćemo ih preskočiti.

4. Dijeljenje resursa s više podrijetla

Korištenjem CORS-a omogućavamo komunikaciju između domena. Najčešći slučaj su AJAX pozivi s druge domene. Prvi pristup koji možemo koristiti je omogućavanje CORS-a za sve naše API-je. Koristiti -žalice argument, omogućit ćemo pristup svim domenama. Također možemo definirati koje domene dopuštamo –Cors = ”// dashboard.myApp.com //admin.myapp.com” . Drugi je pristup omogućiti CORS za pojedine API-je. Pogledajmo kako koristiti addHeader da biste to postigli:
@Override public Response serve (IHTTPSession session) {Response response = newFixedLengthResponse ("Hello world"); response.addHeader ("Access-Control-Allow-Origin", "*"); odgovor na povratak; }

Sad kad mi kovrča, vratit ćemo naše zaglavlje CORS:

> curl -v '// localhost: 8080' HTTP / 1.1 200 OK Tip sadržaja: text / html Datum: Četvrtak, 13. lipnja 2019. 03:58:14 GMT Access-Control-Allow-Origin: * Veza: održavaj u životu Duljina sadržaja: 11 Pozdrav svijete

5. Prijenos datoteke

NanoHTTPD ima zasebnu ovisnost za prijenose datoteka, pa ga dodajte u naš projekt:

 org.nanohttpd nanohttpd-apache-fileupload 2.3.1 javax.servlet javax.servlet-api 4.0.1 pod uvjetom 

Imajte na umu da servlet-api ovisnost je također potrebna (inače ćemo dobiti pogrešku u kompilaciji).

Ono što NanoHTTPD izlaže je klasa tzv NanoFileUpload:

@Override public Response serve (IHTTPSession session) {try {List files = new NanoFileUpload (new DiskFileItemFactory ()). ParseRequest (session); int uploadedCount = 0; za (FileItem datoteka: datoteke) {try {String fileName = file.getName (); bajt [] fileContent = file.get (); Files.write (Paths.get (fileName), fileContent); uploadedCount ++; } catch (iznimka iznimke) {// handle}} return newFixedLengthResponse (Response.Status.OK, MIME_PLAINTEXT, "Učitane datoteke" + uploadedCount + "out" + files.size ()); } catch (IOException | FileUploadException e) {throw new IllegalArgumentException ("Ne mogu obraditi datoteke iz zahtjeva za API", e); } return newFixedLengthResponse (Response.Status.BAD_REQUEST, MIME_PLAINTEXT, "Pogreška prilikom prijenosa"); }

Hej, probajmo:

> curl -F '[zaštićen e-poštom] /pathToFile.txt' '// localhost: 8080' Učitane datoteke: 1

6. Više ruta

A nanolet je poput servleta, ali ima vrlo nizak profil. Pomoću njih možemo definirati mnoge rute koje opslužuje jedan poslužitelj (za razliku od prethodnih primjera s jednom rutom).

Prvo, dodajmo traženu ovisnost za nanolete:

 org.nanohttpd nanohttpd-nanolets 2.3.1 

A sada ćemo proširiti našu glavnu klasu pomoću UsmjerivačNanoHTTPD, definirajte naš port koji radi i neka se poslužitelj pokreće kao demon.

The addMappings metoda definirat ćemo naše rukovatelje:

javna klasa MultipleRoutesExample proširuje RouterNanoHTTPD {public MultipleRoutesExample () baca IOException {super (8080); addMappings (); start (NanoHTTPD.SOCKET_READ_TIMEOUT, netačno); } @Override public void addMappings () {// za ispunjavanje ruta}}

Sljedeći je korak definiranje našeg addMappings metoda. Definirajmo nekoliko rukovatelja.

Prvi je IndexHandler klasa na put “/”. Ova klasa dolazi s knjižnicom NanoHTTPD i vraća se prema zadanim postavkama a Pozdrav svijete poruka. Možemo nadjačati getText metoda kada želimo drugačiji odgovor:

addRoute ("/", IndexHandler.class); // unutar metode addMappings

A da testiramo našu novu rutu možemo učiniti:

> curl '// localhost: 8080' 

Pozdrav svijete!

Drugo, stvorimo novo UserHandler klasa koja proširuje postojeću DefaultHandler. Ruta za to bit će /korisnika. Ovdje smo se poigrali s tekstom, vrstom MIME i vraćenim statusnim kodom:

javna statička klasa UserHandler proširuje DefaultHandler {@Override public String getText () {return "UserA, UserB, UserC"; } @Override javni niz getMimeType () {return MIME_PLAINTEXT; } @Override public Response.IStatus getStatus () {return Response.Status.OK; }}

Da bismo nazvali ovu rutu, izdat ćemo a kovrča narediti ponovo:

> curl -X POST '// localhost: 8080 / users' UserA, UserB, UserC

Napokon, možemo istražiti GeneralHandler s novom StoreHandler razred. Izmijenili smo vraćenu poruku tako da uključuje storeId odjeljak URL-a.

javna statička klasa StoreHandler proširuje GeneralHandler {@Override public Response get (UriResource uriResource, Map urlParams, IHTTPSession session) {return newFixedLengthResponse ("Dohvaćanje trgovine za id =" + urlParams.get ("storeId")); }}

Provjerimo naš novi API:

> curl '// localhost: 8080 / store / 123' Dohvaćanje trgovine za id = 123

7. HTTPS

Da bismo mogli koristiti HTTPS, trebat će nam certifikat. Dodatne detaljnije informacije potražite u našem članku o SSL-u.

Mogli bismo koristiti uslugu poput Let's Encrypt ili jednostavno generirati samopotpisani certifikat kako slijedi:

> keytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass lozinka -validnost 360 -keysize 2048 -ext SAN = DNS: localhost, IP: 127.0.0.1 -validity 9999

Dalje, kopirali bismo ovo pohrana ključeva.jks do mjesta na našoj stazi, kao što je recimo src / glavni / resursi mapa Mavenova projekta.

Nakon toga možemo ga uputiti u pozivu na NanoHTTPD # makeSSLSocketFactory:

javna klasa HttpsExample proširuje NanoHTTPD {public HttpsExample () baca IOException {super (8080); makeSecure (NanoHTTPD.makeSSLSocketFactory ("/keystore.jks", "lozinka" .toCharArray ()), null); start (NanoHTTPD.SOCKET_READ_TIMEOUT, netačno); } // glavne i uslužne metode}

A sada to možemo isprobati. Molimo primijetite upotrebu -nesiguran parametar, jer kovrča prema zadanim postavkama neće moći provjeriti našu samopotpisanu potvrdu:

> curl --insecure '// localhost: 8443' HTTPS poziv je uspješan

8. WebSockets

NanoHTTPD podržava WebSockets.

Stvorimo najjednostavniju implementaciju WebSocket-a. Za ovo ćemo morati proširiti NanoWSD razred. Trebat ćemo dodati i NanoHTTPD ovisnost za WebSocket:

 org.nanohttpd nanohttpd-websocket 2.3.1 

Za našu implementaciju odgovorit ćemo jednostavnim korisnim brojem teksta:

javna klasa WsdExample proširuje NanoWSD {public WsdExample () baca IOException {super (8080); start (NanoHTTPD.SOCKET_READ_TIMEOUT, netačno); } public static void main (String [] args) baca IOException {new WsdExample (); } @Override zaštićen WebSocket openWebSocket (IHTTPSession ihttpSession) {return new WsdSocket (ihttpSession); } privatna statička klasa WsdSocket proširuje WebSocket {javni WsdSocket (IHTTPSession handshakeRequest) {super (handshakeRequest); } // nadjačati onOpen, onClose, onPong i onException metode @Override protected void onMessage (WebSocketFrame webSocketFrame) {try {send (webSocketFrame.getTextPayload () + "to you"); } catch (IOException e) {// handle}}}}

Umjesto kovrča ovaj put, koristit ćemo wscat:

> wscat -c localhost: 8080 pozdrav pozdrav doviđenja doviđenja

9. Zaključak

Da rezimiramo, stvorili smo projekt koji koristi biblioteku NanoHTTPD. Zatim smo definirali RESTful API-je i istražili više HTTP-ovih funkcionalnosti. Na kraju smo implementirali i WebSocket.

Implementacija svih ovih isječaka dostupna je na GitHubu.


$config[zx-auto] not found$config[zx-overlay] not found