如何通过设置CORS允许跨站点请求
在浏览器中运行的JavaScript应用程序通常只能从为其提供服务的同一域(源)中访问HTTP资源。
始终可以加载来自相同来源的图像或脚本/样式。另外,使用@font-face
默认情况下设置了“相同来源”政策。与其他不那么受欢迎的事物(例如WebGL纹理和drawImage
Canvas API中加载的资源)。
但是,对外部第三方服务器的XHR和Fetch调用将失败。除非第三方服务器实施允许建立连接并允许下载和使用所请求资源的机制。
这种机制称为CORS,跨域资源共享。
需要CORS的一件非常重要的事情是ES模块,最近在现代浏览器中引入。
如果您未设置CORS政策在服务器上使其可以服务于第三方来源,该请求将失败。
获取示例:
XHR示例:
跨域资源在以下情况下会失败:
- 换一个领域
- 换一个子域
- 换一个港口
- 换一个协议
CORS可以确保您的安全,以防止恶意用户利用您恰巧正在使用的任何Web平台。
如果同时控制两个服务器和对于客户,您知道双方都是值得信赖的,因此有充分的理由允许资源共享。
如何?
这取决于您的服务器端堆栈。
浏览器支持
相当不错(基本上除IE <10以外的所有内容):
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标头而导致失败的请求。正如您在“网络”面板中看到的那样,您可以在其中看到服务器发送的消息:
仅允许特定来源
但是,此示例有一个问题:服务器将把任何请求作为跨域接受。
正如您在“网络”面板中看到的那样,传递的请求具有一个响应标头access-control-allow-origin: *
:
您需要将服务器配置为仅允许一个来源服务,并阻止所有其他来源。
使用相同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
如果请求满足使用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.comThe 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, DELETEWe 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:
- Express, a popular Node.js Framework
- Retrieve the GET query string parameters using Express
- Validating input in Express using express-validator
- Express Templates
- Serving Static Assets with Express
- Send a JSON response using Express
- Express Sessions
- Send a response using Express
- Send files using Express
- Sanitizing input in Express using express-validator
- Routing in Express
- An Express HTTPS server with a self-signed certificate
- Express, Request Parameters
- Retrieve the POST query parameters using Express
- Handling redirects with Express
- Express Middleware
- Setup Let's Encrypt for Express
- Work with HTTP headers in Express
- Handling forms in Express
- Handling file uploads in forms using Express
- Handling CORS in Express
- Manage Cookies with Express