CORS,跨域資源共享

跨域資源共享簡介,一種使客戶端和服務器即使不在同一域中也可以進行通信的方法

在瀏覽器中運行的JavaScript應用程序通常只能訪問為其提供服務的同一域(源)上的HTTP資源。

始終可以加載圖像或腳本/樣式,但是XHR拿來除非該服務器實現允許該連接的方法,否則對另一台服務器的調用將失敗。

這種方式稱為CORS,跨域資源共享

也使用以下方式加載Web字體@font-face默認情況下具有同源策略,而其他不受歡迎的事物(例如WebGL紋理和drawImageCanvas API中加載的資源)。

需要CORS的一件非常重要的事情是ES模塊,最近在現代瀏覽器中引入。

如果您未設置CORS政策在服務器上允許服務於第三方來源,請求將失敗。

獲取示例:

Fetch failed because of CORS policy

XHR示例:

XHR request failed because of CORS policy

跨域資源在以下情況下會失敗:

  • 換一個領域
  • 換一個子域
  • 換一個港口
  • 換一個協議

而且它的存在是為了確保您的安全,以防止惡意用戶利用網絡平台

但是,如果您同時控制服務器和客戶端,則有充分的理由讓它們彼此通信。

如何?

這取決於您的服務器端堆棧。

瀏覽器支持

相當不錯(基本上除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請求屬於該組。

一些 POSTHEAD請求也是如此。

POST如果請求滿足使用Content-Type的要求,則該請求也屬於此組

  • 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())


More browser tutorials: