cors 跨域资源共享
A JavaScript application running in the browser can usually only access HTTP resources on the same domain (origin) that serves it.
在浏览器中运行JavaScript应用程序通常只能访问为其提供服务的同一个域(源)上的HTTP资源。
Loading images or scripts/styles always works, but XHR and Fetch calls to another server will fail, unless that server implements a way to allow that connection.
始终可以加载图像或脚本/样式,但是XHR和Fetch调用将失败,除非该服务器实现了允许该连接的方式。
This way is called CORS, Cross-Origin Resource Sharing.
这种方式称为CORS, 跨域资源共享 。
Also loading Web Fonts using @font-face
has same-origin policy by default, and other less popular things (like WebGL textures and drawImage
resources loaded in the Canvas API).
默认情况下,也使用@font-face
加载具有相同来源策略的Web字体,以及其他较不流行的功能(例如,在Canvas API中加载的WebGL纹理和drawImage
资源)。
One very important thing that needs CORS is ES Modules, recently introduced in modern browsers.
需要CORS的一项非常重要的事情是ES模块 ,该模块最近在现代浏览器中引入。
If you don’t set up a CORS policy on the server that allows to serve 3rd party origins, the request will fail.
如果您未在允许服务于第三方来源的服务器上设置CORS策略,则请求将失败。
Fetch example:
获取示例:
XHR example:
XHR示例:
A Cross-Origin resource fails if it’s:
跨域资源在以下情况下失败:
to a different domain
到另一个域
to a different subdomain
到另一个子域
to a different port
到另一个端口
to a different protocol
到不同的协议
and it’s there for your security, to prevent malicious users to exploit the Web Platform.
并且为了安全起见,它可以防止恶意用户利用Web平台 。
But if you control both the server and the client, you have all the good reasons to allow them to talk to each other.
但是,如果您同时控制服务器和客户端,则有充分的理由让它们彼此通信。
How?
怎么样?
It depends on your server-side stack.
这取决于您的服务器端堆栈。
浏览器支持 (Browser support)
Pretty good (basically all except IE<10):
相当不错(基本上除IE <10以外的所有内容):
Express的例子 (Example with Express)
If you are using Node.js and Express as a framework, use the CORS middleware package.
如果您使用Node.js和Express作为框架,请使用CORS中间件软件包 。
Here’s a simple implementation of an Express Node.js server:
这是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)
})
If you hit /without-cors
with a fetch request from a different origin, it’s going to raise the CORS issue.
如果您用其他来源的获取请求按/without-cors
with /without-cors
命中,则会引发CORS问题。
All you need to do to make things work out is to require the cors
package linked above, and pass it in as a middleware function to an endpoint request handler:
您需要做的所有事情才能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 */
I made a simple Glitch example, here’s its code: https://glitch.com/edit/#!/flavio-cors-client.
我做了一个简单的Glitch示例,这是它的代码: https ://glitch.com/edit/#!/flavio-cors-client。
This is the Node.js Express server: https://glitch.com/edit/#!/flaviocopes-cors-example-express
这是Node.js Express服务器: https ://glitch.com/edit/#!/flaviocopes-cors-example-express
Note how the request that fails because it does not handle the CORS headings correctly is still received, as you can see in the Network panel, where you find the message the server sent:
请注意,由于仍然无法正确处理CORS标题,因此仍然收到失败的请求,如在“网络”面板中所见,您可以在其中找到服务器发送的消息:
仅允许特定来源 (Allow only specific origins)
This example has a problem however: ANY request will be accepted by the server as cross-origin.
但是,此示例有一个问题:服务器将任何请求作为跨域接收。
As you can see in the Network panel, the request that passed has a response header access-control-allow-origin: *
:
如您在“网络”面板中看到的那样,传递的请求具有响应标头access-control-allow-origin: *
:
You need to configure the server to only allow one origin to serve, and block all the others.
您需要将服务器配置为仅允许一个来源服务,并阻止所有其他来源。
Using the same cors
Node library, here’s how you would do it:
使用相同的cors
Node库,以下是您的操作方法:
const cors = require('cors')
const corsOptions = {
origin: 'https://yourdomain.com',
}
app.get('/products/:id', cors(corsOptions), (req, res, next) => {
//...
})
You can serve more as well:
您还可以提供更多服务:
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'))
}
},
}
飞行前 (Preflight)
There are some requests that are handled in a “simple” way. All GET
requests belong to this group.
有些请求以“简单”的方式处理。 所有GET
请求都属于该组。
Also some POST
and HEAD
requests do as well.
同样, 一些 POST
和HEAD
请求也是如此。
POST
requests are also in this group, if they satisfy the requirement of using a Content-Type of
POST
请求满足使用Content-Type的要求,则也属于该组
application/x-www-form-urlencoded
application/x-www-form-urlencoded
multipart/form-data
multipart/form-data
text/plain
text/plain
All other requests must run through a pre-approval phase, called preflight. The browser does this to determine if it has the permission to perform an action, by issuing an OPTIONS
request.
所有其他请求必须经过称为预检的预批准阶段。 浏览器通过发出OPTIONS
请求来确定是否具有执行操作的权限。
A preflight request contains a few headers that the server will use to check permissions (irrelevant fields omitted):
预检请求包含一些标头,服务器将使用这些标头检查权限(忽略了不相关的字段):
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.
我们检查了POST,但是服务器告诉我们我们还可以为该特定资源发出其他HTTP请求类型。
Following the Node.js Express example above, the server must also handle the OPTIONS request:
按照上面的Node.js Express示例,服务器还必须处理OPTIONS请求:
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())
cors 跨域资源共享