طلب عادي
في الآونة الأخيرة ، يحتاج الآخرون إلى استدعاء وظيفة نظامنا ، ويأمل الطرف الآخر في توفير واجهة برمجة تطبيقات حتى يتمكن من تحديث البيانات. نظرًا لأن هذا زميله هو مطور عميل ، فإن لديه رمزًا مشابهًا لما يلي.
requestmapping (method = requestMethod.post ، value = "/update.json" ، produces = mediaType.application_json_value) publicresponsebody contacter update (requestbody contacterro) == 123) {contacterro.setusername ("adminupdate-wangdachui") ؛} إرجاع contacterro ؛}يبدأ العميل طلب HTTP من خلال رمز للاتصال به. بعد ذلك ، سأل الطالب: كان يأمل في استخدام مكالمات JS من خلال المتصفح ، لذلك كانت هناك مشكلة في المجال.
لماذا النطاق المتقاطع
ببساطة ، يقيد المتصفح الوصول إلى رمز JS ضمن الموقع A لجعل طلب Ajax إلى عنوان URL ضمن الموقع B. إذا كان اسم المجال الحالي هو www.abc.com ، فإن رمز JS الذي يعمل في البيئة الحالية لا يمكنه الوصول إلى الموارد تحت اسم مجال www.zzz.com لأسباب أمنية.
على سبيل المثال: يمكن استخدام الرمز التالي لاستدعاء الواجهة بشكل طبيعي من خلال رمز JS تحت اسم المجال هذا
(function () {var url = "http: // localhost: 8080/api/home/update.json" ؛ var data = {"userId": 123 ، "username": "wangdachui" 'application/json'}). تم (function (result) {console.log ("success") ؛ console.log (result) ؛}). fail (function () {console.log ("error") ؛})}) ()الإخراج هو:
كائن {userId: 123 ، اسم المستخدم: "adminupdate-wangdachui"}ومع ذلك ، فإن الوصول إلى أسماء النطاقات الأخرى سيؤدي إلى خطأ:
الخيارات http: // localhost: 8080/api/home/update.jsonxmlhttprequest لا يمكن تحميل http: // localhost: 8080/api/home/update.json. الاستجابة لطلب Preflight لا تمرر التحقق من التحكم في الوصول: لا يوجد رأس "Access-Control-Orgin-arigin" موجودًا على المورد المطلوب. وبالتالي ، لا يُسمح بالوصول إلى أصل "فارغ". وكان الاستجابة رمز حالة HTTP 403.
حل
JSONP
يعد استخدام JSONP إلى المجال المتقاطع طريقة شائعة نسبيًا ، ولكن عندما يتم كتابة الواجهة ، يجب تحويل كل من الخادم وجانب المكالمات وتوافقه مع الواجهة الأصلية ، وهو أمر كبير جدًا ، لذلك نحن نأخذ في الاعتبار طرقًا أخرى.
بروتوكول CORS
وفقًا للمراجع: تحتاج كل صفحة إلى إرجاع رأس HTTP المسمى "Access-Control-Origin" للسماح بالوصول إلى الموقع في المجال الأجنبي. يمكنك فقط فضح الموارد المحدودة وتوصيل الموقع خارج المجال. في وضع COR ، يمكن وضع مسؤولية التحكم في الوصول في أيدي مطور الصفحة ، وليس مسؤول الخادم. بالطبع ، يحتاج مطورو الصفحات إلى كتابة رمز معالجة خاص للسماح بالوصول إلى العالم الخارجي. يمكننا أن نفهم ذلك على النحو التالي: إذا كان الطلب يحتاج إلى السماح بالوصول عبر المجال ، فأنت بحاجة إلى ضبط Access-Control-Origin في رأس HTTP لتحديد المواقع التي تسمح بالوصول إليها. إذا كنت بحاجة إلى السماح لطلبات من www.foo.com إلى المجال المتقاطع ، فيمكنك تعيين: Access-Control-Ollow-Origin: http://www.foo.com. أو Access-Control-arigin: *. يتم دعم CORS في معظم المتصفحات الحديثة كجزء من HTML5.
لدى CORS الرؤوس المشتركة التالية
Access-Control-allow-Origin: http: //foo.orgaccess-control-max-mage: 3628800access-control-allow-methods: get ، put ، deleteaccess-control- allow-headers: content-type-acontrol-armin-arigin " الطلبات. يشير "Access-Control-Max-age" إلى أنه في غضون 3628800 ثانية ، لا توجد طلبات مسبقة التحقق. تشير النتيجة "Methods-Access-Conmbling-Methods" إلى أنها تسمح بالجائزة أو الحذف وحذف الطلبات الخارجية "رؤساء التربط بين الوصول" إلى أنه يتيح طلبات عبر المجال بتضمين رؤوس من نوع المحتوى
عملية cors الأساسية
أولاً ، يتم إصدار طلب Preflight ، والذي يصدر أولاً طريقة الخيارات وطلب يحتوي على رأس "الأصل" إلى خادم الموارد. يمكن لهذا الرد التحكم في طريقة طلب COR ورأس HTTP ومعلومات التحقق. لن يتم بدء طلب مجال أجنبي حقيقي إلا بعد السماح بالطلب.
Spring MVC يدعم cors
الاستجابة لطلب Preflight لا تمرر التحقق من التحكم في الوصول: لا يوجد رأس "Access-Control-Orgin-arigin" موجودًا على المورد المطلوب. وبالتالي ، لا يُسمح بالوصول إلى أصل "فارغ". وكان الاستجابة رمز حالة HTTP 403.
من رسالة الخطأ أعلاه ، يمكننا أن نرى أن السبب المباشر هو أنه لا يوجد رأس للوصول إلى الأصل في رأس الطلب. لذا فإن فكرتنا المباشرة هي إضافة هذا الرأس إلى رأس الطلب. يمكن للخادم إرجاع 403 ، مما يشير إلى أن الخادم قد قام بالفعل بمعالجة الطلب.
اعتراض MVC
أولاً ، نقوم بتكوين اعتراض لاعتراض الطلب وتسجيل معلومات رأس الطلب.
Debug requesturl: /api/home/update.json طريقة التصحيح: خيارات تصحيح الأخطاء المضيف: LocalHost: 8080 اتصال رأس التصحيح: keep-alive debug header cache cache-control: max-age = 0 debug header account-control-request-method: post debug header header-user-age-ag: AppleWebkit/537.36 (KHTML ، مثل Gecko) Chrome/49.0.2623.87 Safari/537.36 Debug Header Access-Accounder-Reader-request: قبول ، رأس DED-TYPE قبول: قبول اللغة: ZH-CN ، ZH ؛ Q = 0.8 ، en ؛ q = 0.6
وجدت طباعة سجل الدخول إلى ما بعد أن تكون حالة الاستجابة هي 403 في هذا الوقت. وجد تتبع رموز SPRINGMVC أنه في org.springframework.web.servlet.dispatcherservlet.dodispatch ، سيتم الحصول على HandleRexecutionchain بناءً على الطلب. بعد استحواذ SpringMVC على معالج منتظم ، سيتحقق مما إذا كان طلبًا متقاطعًا. إذا كان الأمر كذلك ، فسوف يحل محل المثيل الأصلي.
Overridepublic Final HandleRexecutionchain Gethandler (httpservletrequest) يلقي استثناء {كائن معالج = gethandlerinternal (طلب) ؛ if (handler == null) {handler = getDefaulThandler () ؛} معالجة = (سلسلة) معالج ؛ معالج = getApplicationContext (). getBean (معالجة) ؛} handleRexecutionchain executionchain = gethandleRexecutionchain (Handler ، request) ؛ if (corsutils.iscorsrequest (request)) {corsconfiguration global this.corsconfigSource.getCorsConfiguration (request) ؛ corsconfiguration handlerconfig = getCorsConfiguration (Handler ، request) ؛ corsconfiguration config = (GlobalConfig! = null؟ config) ؛} الإرجاع executionchain ؛}طريقة الفحص بسيطة للغاية ، أي تحقق مما إذا كان هناك حقل أصل في رأس الطلب.
isCorSRequest الثابت العام (طلب httpservletrequest) {return (request.getheader (httpheaders.origin)! = null) ؛}بعد ذلك ، سيتم تسليم الطلب إلى httprequesthandleradapter.handle للمعالجة ، وسيتم معالجة المنطق المختلفة وفقًا للمقبض. يعتمد الحكم السابق على رأس الطلب كطلب عبر المجال. المعالج الذي تم الحصول عليه هو preflighthandler ، والذي يتم تنفيذه على النحو التالي:
Overridepublic void HandleRequest (طلب httpservletrequest ، استجابة httpservletresponse) يلقي ioexception {corsprocessor.processRequest (this.config ، request ، response) ؛}استمر في المتابعة
Overridepublic Boolean ProcessRequest (CorsConfiguration Config ، HttPservletRequest ، استجابة httpservletresponse) يلقي iOexception {if (! corsutils.iscorsrequest (طلب)) {return true ؛ servletserverhttpresponse (استجابة) ؛ servletserverhttprequest serverRequest = new servletserverhttprequest (request) ؛ if (webUtils.issameorigin (serverRequest)) {logger.debug ("تخطي معالجة cors ، يكون الطلب من نفس الأدمغة") preflightrequest = corsuTils.ispRefRefrequest (request) ؛ if (config == null) {if (preflightrequest) {refectRequest (serverResponse) ؛ return false ؛} آخر {return true ؛}}تتحقق هذه الطريقة أولاً ما إذا كان طلبًا متقاطعًا ، وإذا لم يكن كذلك ، فسيعود مباشرة. ثم يتحقق ما إذا كان تحت نفس المجال ، أو ما إذا كان لديه حقل-السموم بالمواصفات-المترجمة في رأس الاستجابة أو ما إذا كان لديه طريقة مرجعية للوصول في الطلب. إذا تم استيفاء حالة الحكم ، يتم رفض الطلب.
من هذا ، نعلم أنه يمكن تمرير الشيك عن طريق ضبط رأس التحكم في الوصول إلى الأصل للاستجابة قبل الشيك. نتعامل مع prehandle في التقاطع. أضف الرمز التالي:
استجابة.
في هذا الوقت ، يرجع طلب الخيارات في المتصفح 200. ولكن لا يزال خطأ:
لا يُسمح بمحتوى حقل حقل الطلب من خلال روابط السموم بالوصول إلى السيطرة في استجابة المبدئي.
لقد لاحظنا أن هناك رؤساء المرجعين للوصول: قبول ، نوع المحتوى في رأس الطلب ، لكن رأس الطلب هذا لا. في هذا الوقت ، لا يرسل المتصفح الطلب كما هو مطلوب. حاول إضافته إلى الرد:
استجابة.
التنفيذ الناجح: كائن {userId: 123 ، اسم المستخدم: "adminupdate-wangdachui"}.
حتى الآن: نستخدم مبدأ التحليل لتمكين SPRINGMVC من تحقيق المجال المتقاطع ، دون أي تغييرات على التنفيذ الأصلي ورمز العميل.
SpringMVC 4
علاوة على ذلك ، في المرجع 2 ، يوفر SpringMVC4 طريقة مريحة للغاية لتنفيذ المجال المتقاطع.
استخدم التعليقات التوضيحية في الطلب. crossorigin (Origins = "http: // localhost: 9000")
التنفيذ العالمي. تعريف الفئة الميراث webmvcconfigureRadapter
الطبقة العامة corsConfigureRadAdapter يمتد webmvcconfigureRadapter {Overridepublic void addCorsMappings (سجل corsregistry) {registry.addmapping ("/api/*"). المسموحات ("*") ؛}}حقن الفصل في الحاوية:
<bean> </ban>
لخص
ما سبق هو كل التفسير المفصل لتنفيذ الربيع ومعالجة رمز طلب المجال المتقاطع. آمل أن يكون ذلك مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!