מדריך ל- NanoHTTPD

1. הקדמה

NanoHTTPD הוא שרת אינטרנט עם קוד פתוח וקל משקל שנכתב ב- Java.

במדריך זה ניצור כמה ממשקי API של REST כדי לחקור את התכונות שלו.

2. הגדרת פרויקט

בואו נוסיף את תלות הליבה של NanoHTTPD שלנו pom.xml:

 org.nanohttpd nanohttpd 2.3.1 

כדי ליצור שרת פשוט, עלינו להאריך NanoHTTPD ולדרוס את שלה לְשָׁרֵת שיטה:

יישום בכיתה ציבורית מרחיב NanoHTTPD {יישום ציבורי () זורק IOException {סופר (8080); התחל (NanoHTTPD.SOCKET_READ_TIMEOUT, שקר); } ציבורי ריק סטטי ציבורי (מחרוזת [] טוען) זורק IOException {אפליקציה חדשה (); } הגשת תגובת הציבור של @Override (הפעלת IHTTPSession) {החזר newFixedLengthResponse ("שלום עולם"); }}

הגדרנו את נמל הריצה שלנו כ- 8080 והשרת לעבוד כדמון (ללא פסק זמן לקריאה).

ברגע שנתחיל את היישום, כתובת ה- URL // localhost: 8080 / יחזיר את שלום עולם הוֹדָעָה. אנחנו משתמשים NanoHTTPD # newFixedLengthResponse שיטה כדרך נוחה לבנות א תגובה NanoHTTPD לְהִתְנַגֵד.

בואו ננסה את הפרויקט שלנו עם cURL:

> תלתל '// localhost: 8080 /' שלום עולם

3. API של REST

בדרך של שיטות HTTP, NanoHTTPD מאפשר GET, POST, PUT, DELETE, HEAD, TRACE, וכמה אחרים.

במילים פשוטות, אנו יכולים למצוא פעלים מסוג HTTP נתמך באמצעות שיטת enum. בואו נראה איך זה משחק.

3.1. HTTP GET

ראשית, בואו נסתכל על GET. אמור, למשל, שאנחנו רוצים להחזיר תוכן רק כאשר היישום מקבל בקשת GET.

שלא כמו מכולות Java Servlet, אין לנו doGet שיטה זמינה - במקום זאת, אנחנו רק בודקים את הערך באמצעות getMethod:

@Override תגובה תגובה ציבורית (הפעלת IHTTPSession) {if (session.getMethod () == Method.GET) {String itemIdRequestParameter = session.getParameters (). Get ("itemId"). Get (0); החזר newFixedLengthResponse ("Required itemId =" + itemIdRequestParameter); } להחזיר newFixedLengthResponse (תגובה.Status.NOT_FOUND, MIME_PLAINTEXT, "המשאב המבוקש לא קיים"); }

זה היה די פשוט, נכון? בוא נבצע בדיקה מהירה על ידי סלסול נקודת הקצה החדשה שלנו ונראה כי פרמטר הבקשה מספר זיהוי של הפריט נקרא נכון:

> curl '// localhost: 8080 /? itemId = 23Bk8' ItemId = 23Bk8 מבוקש

3.2. HTTP POST

בעבר הגבנו ל- GET וקראנו פרמטר מכתובת האתר.

על מנת לכסות את שתי שיטות ה- HTTP הפופולריות ביותר, הגיע הזמן שנטפל ב- POST (ובכך לקרוא את גוף הבקשה):

הגשת הגשת התשובה הציבורית של @Override (הפעלת IHTTPSession) {if (session.getMethod () == Method.POST) {נסה {session.parseBody (HashMap חדש ()); מחרוזת requestBody = session.getQueryParameterString (); להחזיר newFixedLengthResponse ("גוף בקשה =" + requestBody); } לתפוס (IOException | ResponseException e) {// handle}} להחזיר newFixedLengthResponse (Response.Status.NOT_FOUND, MIME_PLAINTEXT, "המשאב המבוקש לא קיים"); }
שימו לב שלפני שביקשנו את גוף הבקשה, קראנו לראשונה parseBody שיטה. הסיבה לכך היא שרצינו לטעון את גוף הבקשה לאחזור מאוחר יותר.

אנו נכלול גוף שלנו סִלְסוּל פקודה:

> תלתל -X POST -d 'deliveryAddress = וושינגטון מס' 4 & כמות = 5 '// localhost: 8080 /' גוף בקשה = משלוח כתובת: וושינגטון מס '4 & כמות = 5

שיטות ה- HTTP הנותרות דומות מאוד באופיין, ולכן נדלג על אותן.

4. שיתוף משאבים בין-מקור

באמצעות CORS אנו מאפשרים תקשורת בין תחומים. מקרה השימוש הנפוץ ביותר הוא שיחות AJAX מתחום אחר. הגישה הראשונה בה אנו יכולים להשתמש היא הפעלת CORS לכל ממשקי ה- API שלנו. משתמש ב -תיקים אנו מאפשרים גישה לכל התחומים. אנו יכולים גם להגדיר אילו תחומים אנו מאפשרים –קורס = ”// dashboard.myApp.com //admin.myapp.com” . הגישה השנייה היא לאפשר CORS עבור ממשקי API בודדים. בואו נראה כיצד להשתמש addHeader כדי להשיג זאת:
הגשת תגובה ציבורית של @Override (הפעלת IHTTPS הפעלה) {תגובה תגובה = newFixedLengthResponse ("שלום עולם"); response.addHeader ("בקרת גישה-אפשר-מקור", "*"); תגובה חזרה; }

עכשיו כשאנחנו סִלְסוּל, נחזיר את כותרת ה- CORS שלנו:

> curl -v '// localhost: 8080' HTTP / 1.1 200 OK סוג תוכן: text / html תאריך: Thu, 13 Jun 2019 03:58:14 GMT בקרת גישה-אפשר-מקור: * חיבור: שמור על החיים אורך תוכן: 11 שלום עולם

5. העלאת קבצים

ל- NanoHTTPD יש תלות נפרדת להעלאת קבצים, אז בואו נוסיף אותו לפרויקט שלנו:

 org.nanohttpd nanohttpd-apache-fileupload 2.3.1 javax.servlet javax.servlet-api 4.0.1 מסופק 

שים לב כי servlet-api יש צורך גם בתלות (אחרת נקבל שגיאת אוסף).

מה שחושף NanoHTTPD הוא מחלקה שנקראת NanoFileUpload:

הגשת הגשת התשובה הציבורית של @Override (הפעלת IHTTPSession) {נסה {List files = new NanoFileUpload (DiskFileItemFactory חדש ()). ParseRequest (session); int uploadedCount = 0; עבור (FileItem file: files) {נסה {String fileName = file.getName (); בתים [] fileContent = file.get (); Files.write (Paths.get (fileName), fileContent); UploadCount ++; } לתפוס (חריג יוצא מן הכלל) {// handle}} להחזיר newFixedLengthResponse (Response.Status.OK, MIME_PLAINTEXT, "קבצים שהועלו" + UploadCount + "מתוך" + files.size ()); } לתפוס (IOException | FileUploadException e) {לזרוק IllegalArgumentException חדש ("לא ניתן היה לטפל בקבצים מבקשת API", e); } להחזיר newFixedLengthResponse (תגובה.Status.BAD_REQUEST, MIME_PLAINTEXT, "שגיאה בעת העלאה"); }

היי, בואו ננסה את זה:

> curl -F '[email protected] / pathToFile.txt' '// localhost: 8080' קבצים שהועלו: 1

6. מספר מסלולים

א ננולט הוא כמו סרוולט אך בעל פרופיל נמוך מאוד. אנו יכולים להשתמש בהם להגדרת מסלולים רבים המשרתים על ידי שרת יחיד (בניגוד לדוגמאות קודמות עם מסלול אחד).

ראשית, בואו נוסיף את התלות הנדרשת עבור ננולטים:

 org.nanohttpd nanohttpd-nanolets 2.3.1 

ועכשיו נרחיב את המעמד הראשי שלנו באמצעות נתב NanoHTTPD, הגדר את יציאת הרצה שלנו והשרת יופעל כדמון.

ה addMappings השיטה היא המקום בו נגדיר את המטפלים שלנו:

מחלקה ציבורית MultipleRoutesExample מרחיב את RouterNanoHTTPD {public MultipleRoutesExample () זורק את IOException {super (8080); addMappings (); התחל (NanoHTTPD.SOCKET_READ_TIMEOUT, שקר); } @Override public void addMappings () {// todo למלא את המסלולים}}

השלב הבא הוא הגדרת שלנו addMappings שיטה. בואו נגדיר כמה מטפלים.

הראשון הוא IndexHandler כיתה לנתיב "/". מחלקה זו מגיעה עם ספריית NanoHTTPD ומחזירה כברירת מחדל א שלום עולם הוֹדָעָה. אנחנו יכולים לעקוף את getText שיטה כשאנחנו רוצים תגובה אחרת:

addRoute ("/", IndexHandler.class); // בתוך שיטת addMappings

וכדי לבדוק את המסלול החדש שלנו אנו יכולים לעשות:

> תלתל '// localhost: 8080' 

שלום עולם!

שנית, בואו ניצור חדש UserHandler מחלקה המרחיבה את הקיים ברירת מחדל. המסלול אליו יהיה /משתמשים. כאן שיחקנו עם הטקסט, סוג MIME וקוד הסטטוס שהוחזר:

מחלקה סטטית ציבורית UserHandler מרחיבה את DefaultHandler {@Override Public String getText () {return "UserA, UserB, UserC"; } @Override מחרוזת ציבורית getMimeType () {להחזיר MIME_PLAINTEXT; } @Override תגובה ציבורית.סטטוס getStatus () {החזר תגובה.Status.OK; }}

כדי להתקשר למסלול זה נפיק א סִלְסוּל פקודה שוב:

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

לבסוף, אנו יכולים לחקור את גנרל האנדלר עם חדש StoreHandler מעמד. שינינו את ההודעה שהוחזרה כך שתכלול את storeId קטע של כתובת האתר.

מחלקה סטטית ציבורית StoreHandler מרחיב את GeneralHandler {@Override Public Response get (UriResource uriResource, Map urlParams, IHTTPSession session) {return newFixedLengthResponse ("אחזור חנות עבור id =" + urlParams.get ("storeId")); }}

בואו נבדוק את ה- API החדש שלנו:

> curl '// localhost: 8080 / stores / 123' מאחזר חנות עבור id = 123

7. HTTPS

על מנת להשתמש ב- HTTPS, נצטרך אישור. אנא עיין במאמר שלנו בנושא SSL למידע מעמיק יותר.

אנו יכולים להשתמש בשירות כמו Let's Encrypt או פשוט ליצור אישור בחתימה עצמית באופן הבא:

> keytool -genkey -keyalg RSA -alias בעצמו-keystore keystore.jks -storepass password -validity 360 -keysize 2048 -ext SAN = DNS: localhost, IP: 127.0.0.1-validity 9999

לאחר מכן, היינו מעתיקים את זה keystore.jks למיקום על מסלול הכיתה שלנו, כמו לומר src / main / resources תיקייה של פרויקט Maven.

לאחר מכן, אנו יכולים להתייחס אליו בשיחה אל NanoHTTPD # makeSSLSocketFactory:

מחלקה ציבורית HttpsExample מרחיב NanoHTTPD {public HttpsExample () זורק IOException {super (8080); makeSecure (NanoHTTPD.makeSSLSocketFactory ("/keystore.jks", "סיסמה" .toCharArray ()), null); התחל (NanoHTTPD.SOCKET_READ_TIMEOUT, שקר); } // ראשי ושיטות הגשה}

ועכשיו נוכל לנסות את זה. אנא שימו לב לשימוש ב- -לֹא בָּטוּחַ פרמטר, כי סִלְסוּל לא יוכל לאמת את האישור שלנו בחתימה עצמית כברירת מחדל:

> curl --insecure '// localhost: 8443' שיחת HTTPS היא הצלחה

8. שקעי רשת

NanoHTTPD תומך ב- WebSockets.

בואו ניצור את היישום הפשוט ביותר של WebSocket. לשם כך נצטרך להאריך את ה- NanoWSD מעמד. נצטרך להוסיף את ה- NanoHTTPD תלות ב- WebSocket:

 org.nanohttpd nanohttpd-websocket 2.3.1 

ליישום שלנו, נשיב רק באמצעות מטען טקסט פשוט:

מחלקה ציבורית WsdExample מרחיב את NanoWSD {public WsdExample () זורק IOException {super (8080); התחל (NanoHTTPD.SOCKET_READ_TIMEOUT, שקר); } ראשי ריק סטטי ציבורי (String [] args) זורק IOException {new WsdExample (); } @Override מוגן WebSocket openWebSocket (IHTTPSession ihttpSession) {להחזיר WsdSocket חדש (ihttpSession); } מחלקה סטטית פרטית WsdSocket מרחיבה את WebSocket {public WsdSocket (IHTTPSession handshakeRequest) {super (handshakeRequest); } // לעקוף שיטות OnOpen, onClose, onPong ו- onException @Override מוגן חלל onMessage (WebSocketFrame webSocketFrame) {נסה {לשלוח (webSocketFrame.getTextPayload () + "לך"); } לתפוס (IOException e) {// handle}}}}

במקום סִלְסוּל הפעם נשתמש wscat:

> wscat -c localhost: 8080 שלום שלום לך להתראות לך

9. מסקנה

לסיכום, יצרנו פרויקט המשתמש בספריית NanoHTTPD. לאחר מכן הגדרנו ממשקי API של RESTful ובחנו פונקציות נוספות הקשורות ל- HTTP. בסופו של דבר, יישמנו גם WebSocket.

היישום של כל התמציות הללו זמין ב- GitHub.


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