جوليا. خدمات الويب


نواصل النظر في تقنيات جوليا. واليوم سوف نتحدث عن الحزم المصممة لبناء خدمات الويب. ليس سراً أن المكانة الرئيسية للغة جوليا هي الحوسبة عالية الأداء. لذلك ، تتمثل الخطوة المنطقية إلى حد ما في إنشاء خدمات ويب مباشرة قادرة على أداء هذه الحسابات عند الطلب. بالطبع ، خدمات الويب ليست هي الطريقة الوحيدة للتواصل في بيئة شبكية. ولكن نظرًا لاستخدامها الآن على نطاق واسع في الأنظمة الموزعة ، فسننظر في إنشاء خدمات تخدم طلبات HTTP.


لاحظ أنه بسبب شباب جوليا ، هناك مجموعة من الحزم المتنافسة. لذلك ، سنحاول معرفة كيف ولماذا استخدامها. على طول الطريق ، قارنا تنفيذ نفس خدمة JSON على شبكة الإنترنت بمساعدتهم.


البنية التحتية لجوليا تم تطوير بنشاط في العام الماضي أو العامين. وفي هذه الحالة ، هذه ليست مجرد عبارة على الإنترنت تم إدراجها لبداية جميلة للنص ، ولكن التأكيد على حقيقة أن كل شيء يتغير بشكل مكثف ، وما كان ذا صلة قبل عامين أصبح الآن قديمًا. ومع ذلك ، سنحاول تسليط الضوء على الحزم المستقرة وتقديم توصيات بشأن كيفية تنفيذ خدمات الويب بمساعدتهم. للتأكد من صحتها ، سنقوم بإنشاء خدمة ويب تقبل طلب POST مع بيانات JSON بالتنسيق التالي:


{ "title": "something", "body": "something" } 

نحن نفترض أن الخدمة التي ننشئها ليست راقية. مهمتنا الرئيسية هي النظر بدقة في طرق وصف الطرق وطالبي المعالجات.


حزمة HTTP.jl


هذه الحزمة هي التطبيق الرئيسي لبروتوكول HTTP في جوليا وتغمر تدريجيا مع ميزات جديدة. بالإضافة إلى تنفيذ هياكل ووظائف نموذجية لتنفيذ طلبات عميل HTTP ، تنفذ هذه الحزمة أيضًا وظائف لإنشاء خوادم HTTP. في الوقت نفسه ، مع تطورها ، تلقت الحزمة وظائف تجعلها مناسبة تمامًا للمبرمج لتسجيل معالجات وبالتالي بناء خدمات نموذجية. أيضًا ، في أحدث الإصدارات ، يوجد دعم مضمن لبروتوكول WebSocket ، والذي تم تنفيذه مسبقًا كجزء من حزمة منفصلة WebSocket.jl. وهذا هو ، HTTP.jl ، في الوقت الحاضر ، يمكن أن تلبي معظم احتياجات مبرمج. دعونا نلقي نظرة على بعض الأمثلة بمزيد من التفصيل.


عميل HTTP


نبدأ التنفيذ برمز العميل ، والذي سنستخدمه للتحقق من قابلية التشغيل.


 #!/usr/bin/env julia --project=@. import HTTP import JSON.json const PORT = "8080" const HOST = "127.0.0.1" const NAME = "Jemand" #    struct Document title::String body::String end #         Base.show(r::HTTP.Messages.Response) = println(r.status == 200 ? String(r.body) : "Error: " * r.status) #    r = HTTP.get("http://$(HOST):$(PORT)") show(r) #   /user/:name r = HTTP.get("http://$(HOST):$(PORT)/user/$(NAME)"; verbose=1) show(r) #  JSON- POST- doc = Document("Some document", "Test document with some content.") r = HTTP.post( "http://$(HOST):$(PORT)/resource/process", [("Content-Type" => "application/json")], json(doc); verbose=3) show(r) 

توفر حزمة HTTP أساليب تتطابق مع أسماء أوامر بروتوكول HTTP. في هذه الحالة ، نستخدم get و post . يتيح لك verbose المسمى اختياريًا تعيين مقدار معلومات التصحيح لإخراجها. لذلك ، على سبيل المثال ، ينتج verbose=1 :


 GET /user/Jemand HTTP/1.1 HTTP/1.1 200 OK <= (GET /user/Jemand HTTP/1.1) 

وفي حالة verbose=3 حصلنا بالفعل على مجموعة كاملة من البيانات المرسلة والمستلمة:


 DEBUG: 2019-04-21T22:40:40.961 eb4f ️-> "POST /resource/process HTTP/1.1\r\n" (write) DEBUG: 2019-04-21T22:40:40.961 eb4f ️-> "Content-Type: application/json\r\n" (write) DEBUG: 2019-04-21T22:40:40.961 eb4f ️-> "Host: 127.0.0.1\r\n" (write) DEBUG: 2019-04-21T22:40:40.961 eb4f ️-> "Content-Length: 67\r\n" (write) DEBUG: 2019-04-21T22:40:40.961 eb4f ️-> "\r\n" (write) DEBUG: 2019-04-21T22:40:40.961 e1c6 ️-> "{\"title\":\"Some document\",\"body\":\"Test document with some content.\"}" (unsafe_write) DEBUG: 2019-04-21T22:40:40.963 eb4f ️<- "HTTP/1.1 200 OK\r\n" (readuntil) DEBUG: "Content-Type: application/json\r\n" DEBUG: "Transfer-Encoding: chunked\r\n" DEBUG: "\r\n" DEBUG: 2019-04-21T22:40:40.963 eb4f ️<- "5d\r\n" (readuntil) DEBUG: 2019-04-21T22:40:40.963 eb4f ️<- "{\"body\":\"Test document with some content.\",\"server_mark\":\"confirmed\",\"title\":\"Some document\"}" (unsafe_read) DEBUG: 2019-04-21T22:40:40.968 eb4f ️<- "\r\n" (readuntil) DEBUG: "0\r\n" DEBUG: 2019-04-21T22:40:40.968 eb4f ️<- "\r\n" (readuntil) 

في المستقبل ، سوف نستخدم verbose=1 فقط لرؤية الحد الأدنى من المعلومات حول ما يحدث.


بعض التعليقات بخصوص الكود.


 doc = Document("Some document", "Test document with some content.") 

نظرًا لأننا أعلنا سابقًا عن بنية المستند (علاوة على ذلك ، غير قابل للتغيير) ، فإن المُنشئ متاح له افتراضيًا ، حيث تتوافق الوسيطات مع الحقول المعلنة للبنية. لتحويلها إلى JSON ، نستخدم حزمة JSON.jl وطريقة json(doc) .
إيلاء الاهتمام للجزء:


 r = HTTP.post( "http://$(HOST):$(PORT)/resource/process", [("Content-Type" => "application/json")], json(doc); verbose=3) 

نظرًا لأننا application/json JSON ، يجب عليك تحديد application/json في رأس Content-Type . يتم تمرير الرؤوس إلى أسلوب HTTP.post (مثل كل الآخرين) باستخدام صفيف (من النوع Vector ، ولكن ليس Dict) يحتوي على أزواج قيمة اسم الرأس.


لإجراء اختبار صحي ، سنقوم بإجراء ثلاثة استفسارات:


  • طلب الحصول على مسار الجذر ؛
  • الحصول على طلب بالتنسيق / المستخدم / الاسم ، حيث يكون الاسم هو الاسم المنقول ؛
  • POST request / resource / process مع تمرير كائن JSON. نتوقع استلام نفس المستند ، ولكن مع إضافة حقل server_mark .

سنستخدم رمز العميل هذا لاختبار جميع خيارات تنفيذ الخادم.


خادم HTTP


بعد معرفة العميل ، حان الوقت لبدء تنفيذ الخادم. بادئ ذي بدء ، سوف نجعل الخدمة فقط بمساعدة HTTP.jl من أجل الحفاظ عليها كخيار أساسي ، والذي لا يتطلب تثبيت حزم أخرى. نذكرك أن جميع الحزم الأخرى تستخدم HTTP.jl


 #!/usr/bin/env julia --project=@. import Sockets import HTTP import JSON #    #    index(req::HTTP.Request) = HTTP.Response(200, "Hello World") #     function welcome_user(req::HTTP.Request) # dump(req) user = "" if (m = match( r".*/user/([[:alpha:]]+)", req.target)) != nothing user = m[1] end return HTTP.Response(200, "Hello " * user) end #  JSON function process_resource(req::HTTP.Request) # dump(req) message = JSON.parse(String(req.body)) @info message message["server_mark"] = "confirmed" return HTTP.Response(200, JSON.json(message)) end #      const ROUTER = HTTP.Router() HTTP.@register(ROUTER, "GET", "/", index) HTTP.@register(ROUTER, "GET", "/user/*", welcome_user) HTTP.@register(ROUTER, "POST", "/resource/process", process_resource) HTTP.serve(ROUTER, Sockets.localhost, 8080) 

في المثال ، يجب الانتباه إلى الكود التالي:


 dump(req) 

يطبع إلى وحدة التحكم كل ما يعرفه الكائن. بما في ذلك أنواع البيانات والقيم ، وكذلك جميع الحقول المتداخلة وقيمها. هذه الطريقة مفيدة لكل من البحث في المكتبة وتصحيح الأخطاء.


صف


 (m = match( r".*/user/([[:alpha:]]+)", req.target)) 

هو تعبير عادي يوزع المسار الذي تم تسجيل المعالج عليه. HTTP.jl توفر حزمة HTTP.jl طرقًا أوتوماتيكية لتحديد نمط في المسار.


داخل معالج process_resource ، نقوم بتحليل JSON المقبولة من قبل الخدمة.


 message = JSON.parse(String(req.body)) 

يتم الوصول إلى البيانات من خلال حقل req.body . لاحظ أن البيانات تأتي بتنسيق صفيف بايت. لذلك ، للعمل معهم كسلسلة ، يتم إجراء تحويل صريح إلى سلسلة. طريقة JSON.jl هي طريقة حزمة JSON.jl تعمل على إلغاء تسلسل البيانات وإنشاء كائن. نظرًا لأن الكائن في هذه الحالة عبارة عن صفيف ترابطي (Dict) ، يمكننا بسهولة إضافة مفتاح جديد إليه. صف


 message["server_mark"] = "confirmed" 

يضيف مفتاح server_mark مع confirmed القيمة.


HTTP.serve(ROUTER, Sockets.localhost, 8080) الخدمة عند HTTP.serve(ROUTER, Sockets.localhost, 8080) خط HTTP.serve(ROUTER, Sockets.localhost, 8080) .


استجابة التحكم للخدمة المستندة إلى HTTP.jl (تم الحصول عليها عند تشغيل رمز العميل مع verbose=1 ):


 GET / HTTP/1.1 HTTP/1.1 200 OK <= (GET / HTTP/1.1) Hello World GET /user/Jemand HTTP/1.1 HTTP/1.1 200 OK <= (GET /user/Jemand HTTP/1.1) Hello Jemand POST /resource/process HTTP/1.1 HTTP/1.1 200 OK <= (POST /resource/process HTTP/1.1) {"body":"Test document with some content.","server_mark":"confirmed","title":"Some document"} 

على خلفية معلومات تصحيح الأخطاء باستخدام verbose=1 ، يمكننا أن نرى بوضوح الخطوط: Hello World ، Hello Jemand ، "server_mark":"confirmed" .


بعد عرض رمز الخدمة ، ينشأ سؤال طبيعي - لماذا نحتاج إلى جميع الحزم الأخرى ، إذا كان كل شيء بسيطًا للغاية في HTTP. هناك إجابة بسيطة جدا لهذا. HTTP - يسمح بتسجيل المعالجات الديناميكية ، ولكن حتى التنفيذ الأولي لقراءة ملف صورة ثابت من دليل يتطلب تطبيق منفصل. لذلك ، فإننا نعتبر أيضًا الحزم التي تركز على إنشاء تطبيقات الويب.


حزمة Mux.jl


تم وضع هذه الحزمة كطبقة وسيطة لتطبيقات الويب المنفذة على جوليا. تنفيذها خفيف الوزن جدا. الغرض الرئيسي هو توفير وسيلة سهلة لوصف معالجات. لا يمكن القول أن المشروع لا يتطور ، لكنه يتطور ببطء. ومع ذلك ، انظر إلى رمز خدمتنا التي تخدم نفس الطرق.


 #!/usr/bin/env julia --project=@. using Mux using JSON @app test = ( Mux.defaults, page(respond("<h1>Hello World!</h1>")), page("/user/:user", req -> "<h1>Hello, $(req[:params][:user])!</h1>"), route("/resource/process", req -> begin message = JSON.parse(String(req[:data])) @info message message["server_mark"] = "confirmed" return Dict( :body => JSON.json(message), :headers => [("Content-Type" => "application/json")] ) end), Mux.notfound() ) serve(test, 8080) Base.JLOptions().isinteractive == 0 && wait() 

هنا يتم وصف الطرق باستخدام طريقة page . تم الإعلان عن تطبيق الويب باستخدام الماكرو @app . الوسائط إلى طريقة page هي الطريق والمعالج. يمكن تحديد معالج كدالة تقبل طلبًا كمدخل ، أو يمكن تحديده كدالة lambda في مكانها. من الوظائف المفيدة الإضافية ، يوجد Mux.notfound() لإرسال استجابة Not found يتم Not found المحددة. والنتيجة التي يجب إرسالها إلى العميل لا تحتاج إلى أن يتم تعبئتها في HTTP.Response ، كما فعلنا في المثال السابق ، لأن Mux سيقوم بذلك بنفسه. ومع ذلك ، لا يزال يتعين عليك إجراء تحليل JSON بنفسك ، وكذلك إجراء تسلسل الكائن للاستجابة - JSON.json(message) .


  message = JSON.parse(String(req[:data])) message["server_mark"] = "confirmed" return Dict( :body => JSON.json(message), :headers => [("Content-Type" => "application/json")] ) 

يتم إرسال الاستجابة كصفيف اقتران مع الحقول :body :headers .


بدء تشغيل الخادم باستخدام طريقة العرض serve(test, 8080) غير متزامن ، لذا فإن أحد الخيارات في جوليا لتنظيم انتظار الإكمال هو الاتصال بالرمز:


 Base.JLOptions().isinteractive == 0 && wait() 

خلاف ذلك ، فإن الخدمة تفعل نفس الإصدار السابق على HTTP.jl


استجابة التحكم للخدمة:


 GET / HTTP/1.1 HTTP/1.1 200 OK <= (GET / HTTP/1.1) <h1>Hello World!</h1> GET /user/Jemand HTTP/1.1 HTTP/1.1 200 OK <= (GET /user/Jemand HTTP/1.1) <h1>Hello, Jemand!</h1> POST /resource/process HTTP/1.1 HTTP/1.1 200 OK <= (POST /resource/process HTTP/1.1) {"body":"Test document with some content.","server_mark":"confirmed","title":"Some document"} 

حزمة Bukdu.jl


تم تطوير الحزمة تحت تأثير إطار عمل Phoenix ، والذي بدوره يتم تنفيذه على Elixir ، ويتم تطبيق أفكار بناء الويب من مجتمع Ruby في عرض على Elixir. يتطور المشروع بنشاط كبير ويتم وضعه كأداة لإنشاء واجهة برمجة تطبيقات RESTful وتطبيقات الويب خفيفة الوزن. هناك وظائف لتبسيط JSON التسلسل وإلغاء التسلسل. هذا مفقود في HTTP.jl و Mux.jl دعونا نلقي نظرة على تنفيذ خدمة الويب لدينا.


 #!/usr/bin/env julia --project=@. using Bukdu using JSON #   struct WelcomeController <: ApplicationController conn::Conn end #   index(c::WelcomeController) = render(JSON, "Hello World") welcome_user(c::WelcomeController) = render(JSON, "Hello " * c.params.user) function process_resource(c::WelcomeController) message = JSON.parse(String(c.conn.request.body)) @info message message["server_mark"] = "confirmed" render(JSON, message) end #   routes() do get("/", WelcomeController, index) get("/user/:user", WelcomeController, welcome_user, :user => String) post("/resource/process", WelcomeController, process_resource) end #   Bukdu.start(8080) Base.JLOptions().isinteractive == 0 && wait() 

أول شيء يجب الانتباه إليه هو إعلان الهيكل لتخزين حالة جهاز التحكم.


 struct WelcomeController <: ApplicationController conn::Conn end 

في هذه الحالة ، هو نوع ملموس تم إنشاؤه كنسل من النوع التجريدي ApplicationController .


يتم الإعلان عن أساليب وحدة التحكم بطريقة مماثلة فيما يتعلق بالتطبيقات السابقة. يوجد اختلاف بسيط في معالج كائن JSON الخاص بنا.


 function process_resource(c::WelcomeController) message = JSON.parse(String(c.conn.request.body)) @info message message["server_mark"] = "confirmed" render(JSON, message) end 

كما ترون ، تتم عملية إلغاء التسلسل أيضًا بشكل مستقل باستخدام طريقة JSON.parse ، لكن طريقة render(JSON, message) JSON.parse تُستخدم لتسلسل الاستجابة.


يتم الإعلان عن الطرق بالطريقة التقليدية للركاب ، بما في ذلك استخدام do...end block.


 routes() do get("/", WelcomeController, index) get("/user/:user", WelcomeController, welcome_user, :user => String) post("/resource/process", WelcomeController, process_resource) end 

أيضًا ، بالطريقة التقليدية للراوبيك ، يتم الإعلان عن جزء في خط المسار /user/:user . بمعنى آخر ، الجزء المتغير من التعبير ، يمكن الوصول إليه بالاسم المحدد في القالب. تم تعيينه بناءً على ذلك كممثل للنوع Symbol . بالمناسبة ، بالنسبة لجوليا ، يعني النوع Symbol ، في جوهره ، نفس الشيء بالنسبة لروبي - هذه سلسلة ثابتة ، يتم تمثيلها في الذاكرة بواسطة مثيل واحد.


وفقًا لذلك ، بعد أن أعلنا طريقًا يحتوي على جزء متغير ، وأشار أيضًا إلى نوع هذا الجزء المتغير ، يمكننا الرجوع إلى البيانات التي تم تحليلها بالفعل بواسطة الاسم المحدد. في الطريقة التي تعالج الطلب ، يمكننا ببساطة الوصول إلى الحقل من خلال نقطة في النموذج c.params.user .


 welcome_user(c::WelcomeController) = render(JSON, "Hello " * c.params.user) 

استجابة التحكم للخدمة:


 GET / HTTP/1.1 HTTP/1.1 200 OK <= (GET / HTTP/1.1) "Hello World" GET /user/Jemand HTTP/1.1 HTTP/1.1 200 OK <= (GET /user/Jemand HTTP/1.1) "Hello Jemand" POST /resource/process HTTP/1.1 HTTP/1.1 200 OK <= (POST /resource/process HTTP/1.1) {"body":"Test document with some content.","server_mark":"confirmed","title":"Some document"} 

استنتاج الخدمة إلى وحدة التحكم:


 >./bukdu_json.jl INFO: Bukdu Listening on 127.0.0.1:8080 INFO: GET WelcomeController index 200 / INFO: GET WelcomeController welcome_user 200 /user/Jemand INFO: Dict{String,Any}("body"=>"Test document with some content.","title"=>"Some document") INFO: POST WelcomeController process_resource200 /resource/process 

حزمة Genie.jl


مشروع طموح تم وضعه كإطار عمل MVC على الويب. في نهجه ، تكون "القضبان" في جوليا واضحة للعيان ، بما في ذلك بنية الدليل التي أنشأها المولد. المشروع قيد التطوير ، ومع ذلك ، لأسباب غير معروفة ، لا يتم تضمين هذه الحزمة في مستودع حزمة جوليا. وهذا يعني أن التثبيت الخاص به ممكن فقط من مستودع git باستخدام الأمر:


 julia>] # switch to pkg> mode pkg> add https://github.com/essenciary/Genie.jl 

رمز خدمتنا في Genie هو كما يلي (لا نستخدم المولدات الكهربائية):


 #!/usr/bin/env julia --project=@. #     import Genie import Genie.Router: route, @params, POST import Genie.Requests: jsonpayload, rawpayload import Genie.Renderer: json! #      route("/") do "Hello World!" end route("/user/:user") do "Hello " * @params(:user) end route("/resource/process", method = POST) do message = jsonpayload() # if message == nothing # dump(Genie.Requests.rawpayload()) # end message["server_mark"] = "confirmed" return message |> json! end #   Genie.AppServer.startup(8080) Base.JLOptions().isinteractive == 0 && wait() 

هنا يجب الانتباه إلى تنسيق الإعلان.


 route("/") do "Hello World!" end 

هذا الرمز مألوف جدا لمبرمجي روبي. كتلة do...end كمعالج وتوجيه كوسيطة للأسلوب. لاحظ أنه بالنسبة لجوليا ، يمكن إعادة كتابة هذا الرمز في النموذج:


 route(req -> "Hello World!", "/") 

وهذا هو ، وظيفة المعالج في المقام الأول ، والطريق هو في الثانية. لكن بالنسبة لحالتنا ، دعنا نترك أسلوب الياقوت.


يقوم Genie تلقائيًا بتعبئة نتيجة التنفيذ في استجابة HTTP. في الحالة الأدنى ، نحتاج فقط إلى إرجاع نتيجة النوع الصحيح ، على سبيل المثال String. من وسائل الراحة الإضافية ، يتم تنفيذ التحقق التلقائي من تنسيق الإدخال وتحليله. على سبيل المثال ، بالنسبة لـ JSON ، تحتاج فقط إلى استدعاء طريقة jsonpayload() .


 route("/resource/process", method = POST) do message = jsonpayload() # if message == nothing # dump(Genie.Requests.rawpayload()) # end message["server_mark"] = "confirmed" return message |> json! end 

إيلاء الاهتمام لجزء كود علق هنا. nothing تُرجع طريقة jsonpayload() nothing إذا لم يتم التعرف على تنسيق الإدخال لسبب JSON لسبب ما. لاحظ أنه لهذا الغرض فقط ، يتم إضافة العنوان [("Content-Type" => "application/json")] إلى عميل HTTP الخاص بنا ، وإلا فلن يبدأ Genie في تحليل البيانات كـ JSON. في حالة حدوث شيء غير مفهوم ، فمن المفيد أن ننظر إلى rawpayload() لمعرفة ما هو عليه. ومع ذلك ، نظرًا لأن هذه مجرد مرحلة تصحيح ، يجب ألا تتركها في التعليمات البرمجية.


أيضًا ، يجب الانتباه إلى إرجاع النتيجة في message |> json! التنسيق message |> json! . يتم وضع طريقة json!(str) في خط الأنابيب هنا. يوفر تسلسل البيانات بتنسيق JSON ، ويضمن أيضًا أن يضيف Genie Content-Type الصحيح. أيضا ، انتبه إلى حقيقة أن كلمة return في معظم الحالات في الأمثلة المذكورة أعلاه لا لزوم لها. جوليا ، مثل روبي ، على سبيل المثال ، ترجع دائمًا نتيجة العملية الأخيرة أو قيمة آخر تعبير محدد. وهذا هو ، كلمة return هو اختياري.


قدرات Genie لا تنتهي عند هذا الحد ، لكننا لسنا بحاجة إليها لتنفيذ خدمة ويب.


استجابة التحكم للخدمة:


 GET / HTTP/1.1 HTTP/1.1 200 OK <= (GET / HTTP/1.1) Hello World! GET /user/Jemand HTTP/1.1 HTTP/1.1 200 OK <= (GET /user/Jemand HTTP/1.1) Hello Jemand POST /resource/process HTTP/1.1 HTTP/1.1 200 OK <= (POST /resource/process HTTP/1.1) {"body":"Test document with some content.","server_mark":"confirmed","title":"Some document"} 

استنتاج الخدمة إلى وحدة التحكم:


 >./genie_json.jl [ Info: Ready! 2019-04-24 17:18:51:DEBUG:Main: Web Server starting at http://127.0.0.1:8080 2019-04-24 17:18:51:DEBUG:Main: Web Server running at http://127.0.0.1:8080 2019-04-24 17:19:21:INFO:Main: / 200 2019-04-24 17:19:21:INFO:Main: /user/Jemand 200 2019-04-24 17:19:22:INFO:Main: /resource/process 200 

حزمة JuliaWebAPI.jl


تم وضع هذه الحزمة كطبقة وسيطة لإنشاء تطبيقات الويب في تلك الأيام عندما كان HTTP.jl مجرد مكتبة تنفذ البروتوكول. قام مؤلف هذه الحزمة أيضًا بتطبيق مولد كود الخادم استنادًا إلى مواصفات Swagger (OpenAPI و http://editor.swagger.io/ ) - راجع المشروع https://github.com/JuliaComputing/Swagger.jl ، واستخدم هذا المولد JuliaWebAPI .jl. ومع ذلك ، فإن المشكلة في JuliaWebAPI.jl هي أنها لا تنفذ القدرة على معالجة نص الطلب (على سبيل المثال ، JSON) المرسلة إلى الخادم من خلال طلب POST. اعتقد المؤلف أن تمرير المعلمات بتنسيق قيمة المفتاح مناسب لجميع المناسبات ... مستقبل هذه الحزمة غير واضح. يتم تطبيق جميع وظائفها بالفعل في العديد من الحزم الأخرى ، بما في ذلك HTTP.jl. الحزمة Swagger.jl أيضًا لم تعد تستخدمها.


WebSockets.jl


تطبيق مبكر لبروتوكول WebSocket. تم استخدام الحزمة لفترة طويلة كتطبيق رئيسي لهذا البروتوكول ، ومع ذلك ، يتم تضمين تنفيذه في الوقت الحالي في حزمة HTTP.jl. تستخدم حزمة WebSockets.jl نفسها HTTP.jl لتأسيس اتصال ، لكن الآن لا يستحق استخدامه في التطورات الجديدة. يجب اعتباره حزمة للتوافق.


استنتاج


توضح هذه المراجعة الطرق المختلفة لتنفيذ خدمة ويب على جوليا. الطريقة الأسهل والأكثر عالمية هي استخدام حزمة HTTP.jl مباشرة. أيضا ، حزم Bukdu.jl و Genie.jl مفيدة جدا. كحد أدنى ، ينبغي رصد تطورها. فيما يتعلق بحزمة Mux.jl ، يتم الآن حل مزاياه على خلفية HTTP.jl. لذلك ، الرأي الشخصي هو عدم استخدامه. Genie.jl هو إطار واعد للغاية. ومع ذلك ، قبل البدء في استخدامه ، يجب أن تفهم على الأقل سبب عدم تسجيل المؤلف كحزمة رسمية.


لاحظ أنه تم استخدام رمز إلغاء تسلسل JSON في الأمثلة دون معالجة الأخطاء. في جميع الحالات باستثناء Genie ، من الضروري التعامل مع أخطاء التحليل وإبلاغ المستخدم بهذا. مثال على هذا الرمز لـ HTTP.jl:


  local message = nothing local body = IOBuffer(HTTP.payload(req)) try message = JSON.parse(body) catch err @error err.msg return HTTP.Response(400, string(err.msg)) end 

بشكل عام ، يمكننا القول أن هناك بالفعل ما يكفي من الأموال لإنشاء خدمات الويب في جوليا. هذا هو ، ليست هناك حاجة إلى "إعادة اختراع العجلة" لكتابتها. والخطوة التالية هي تقييم كيف تستطيع جوليا تحمل العبء في المعايير الحالية ، إذا كان شخص ما على استعداد لتحمله. ومع ذلك ، دعونا الآن نتناول هذا الاستعراض.


مراجع


Source: https://habr.com/ru/post/ar449338/


All Articles