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: