التعامل مع CORS في Express

كيفية السماح بطلبات عبر المواقع من خلال إعداد CORS

عادةً ما يمكن لتطبيق JavaScript قيد التشغيل في المستعرض الوصول فقط إلى موارد HTTP من نفس المجال (الأصل) الذي يخدمهم.

يتم دائمًا تحميل الصور أو البرامج النصية / الأنماط من نفس الأصل. أيضا ، تحميل خطوط الويب باستخدام@font-faceتعيين سياسة "نفس الأصل" افتراضيًا. وبالمثل مع الأشياء الأخرى الأقل شيوعًا (مثل زخارف WebGL وdrawImageالموارد التي تم تحميلها في Canvas API).

ومع ذلك ، ستفشل مكالمات XHR و Fetch إلى خادم خارجي تابع لجهة خارجية. هذا ما لم ينفذ خادم الطرف الثالث آلية تسمح بإجراء الاتصال وتنزيل الموارد المطلوبة واستخدامها.

هذه الآلية تسمىكورسوتبادل الموارد عبر المنشأ.

أحد الأشياء المهمة جدًا التي تحتاج إلى CORS هووحدات ES، تم طرحه مؤخرًا في المتصفحات الحديثة.

إذا لم تقم بإعداد سياسة CORSعلى الخادمالذي يسمح لها بخدمة أصول الطرف الثالث ، فسيفشل الطلب.

مثال على الجلب:

Fetch failed because of CORS policy

مثال XHR:

XHR request failed because of CORS policy

يفشل مورد متعدد الأصول إذا كان:

  • إلى مختلفنطاق
  • إلى مختلفالمجال الفرعي
  • إلى مختلفميناء
  • إلى مختلفبروتوكول

CORS موجود لأمنك ، لمنع المستخدمين المؤذيين من استغلال أي منصة ويب تصادف أنك تستخدمها.

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

كيف؟

يعتمد ذلك على مكدس جانب الخادم الخاص بك.

دعم المتصفح

جيد جدًا (الكل بشكل أساسي باستثناء IE <10):

CORS browser support

مثال مع Express

إذا كنت تستخدم Node.js و Express كإطار عمل ، فاستخدم ملحقحزمة البرامج الوسيطة CORS.

فيما يلي تطبيق بسيط لخادم Express Node.js:

const express = require('express')
const app = express()

app.get(’/without-cors’, (req, res, next) => { res.json({ msg: ‘😞 no CORS, no party!’ }) })

const server = app.listen(3000, () => { console.log(‘Listening on port %s’, server.address().port) })

إذا ضربت/without-corsمع طلب جلب من أصل مختلف ، فسيؤدي ذلك إلى إثارة مشكلة CORS.

كل ما عليك فعله لجعل الأشياء تعمل بسلاسة ، هو أن تطلبcorsالحزمة المرتبطة أعلاه ، وقم بتمريرها كوظيفة وسيطة إلى معالج طلب نقطة النهاية:

const express = require('express')
const cors = require('cors')
const app = express()

app.get(’/with-cors’, cors(), (req, res, next) => { res.json({ msg: ‘WHOAH with CORS it works! 🔝 🎉’ }) })

/* the rest of the app */

لقد قدمت مثالًا بسيطًا لـ Glitch ، إليك رمزه:https://glitch.com/edit/#!/flavio-cors-client.

هذا هو خادم Node.js Express:https://glitch.com/edit/#!/flaviocopes-cors-example-express

لاحظ كيف أن الطلب الذي فشل لأن الخادم لا يعالج رؤوس CORS بشكل صحيح ، لا يزال مستلمًا. كما ترى في لوحة الشبكة ، حيث يمكنك رؤية رسالة أرسلها الخادم:

No response from CORS

السماح بأصول محددة فقط

ومع ذلك ، فإن هذا المثال به مشكلة: سيتم قبول أي طلب من قبل الخادم باعتباره أصل مشترك.

كما ترى في لوحة الشبكة ، فإن الطلب الذي تم تمريره له رأس استجابةaccess-control-allow-origin: *:

The CORS response header

تحتاج إلى تكوين الخادم للسماح لمصدر واحد فقط بالخدمة ، وحظر كل الآخرين.

باستخدام نفس الشيءcorsمكتبة العقدة ، وإليك كيفية القيام بذلك:

const cors = require('cors')

const corsOptions = { origin: https://yourdomain.com, }

app.get(’/products/:id’, cors(corsOptions), (req, res, next) => { //… })

يمكنك تقديم المزيد أيضًا:

const whitelist = ['http://example1.com', 'http://example2.com']
const corsOptions = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  },
}

الاختبار المبدئي

هناك بعض الطلبات التي يتم التعامل معها بطريقة "بسيطة". الجميعGETالطلبات تنتمي إلى هذه المجموعة.

أيضابعض POSTوHEADالطلبات تفعل كذلك.

POSTالطلبات موجودة أيضًا في هذه المجموعة ، إذا كانت تفي بمتطلبات استخدام نوع المحتوى

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

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

يحتوي طلب الاختبار المبدئي على عدد قليل من الرؤوس التي سيستخدمها الخادم للتحقق من الأذونات (تم حذف الحقول غير ذات الصلة):

OPTIONS /the/resource/you/request
Access-Control-Request-Method: POST
Access-Control-Request-Headers: origin, x-requested-with, accept
Origin: https://your-origin.com

The server will respond with something like this (irrelevant fields omitted):

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://your-origin.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE

We checked for POST, but the server tells us we can also issue other HTTP request types for that particular resource.

Following the Node.js Express example above, the server must also handle the OPTIONS request:

var express = require('express')
var cors = require('cors')
var app = express()

//allow OPTIONS on just one resource app.options(’/the/resource/you/request’, cors())

//allow OPTIONS on all resources app.options(’*’, cors())

Download my free Express.js Handbook


More express tutorials: