什么是CORS(跨源资源共享)?
CORS(Cross-Origin Resource Sharing)是一种机制,允许网页从不同的域访问服务器上的资源。
在同源策略下,浏览器限制了跨域访问,CORS允许服务器指定哪些源可以访问其资源。
同源策略(Same-origin policy)
同源策略在web应用安全模型中是一个重要的概念。在这个策略下,浏览器允许第一个网页中包含的脚本可以获取第二个网页的数据,前提是这两个网页在同一个源下。
同源:需要URI、主机名、端口都相同。
这个策略可以防止一个网页上的恶意脚本通过DOM获取其他网页的敏感数据。
需要牢记的一点就是同源策略只应用于脚本,这意味着像images、css和其他动态加载的脚本 可以通过对应的标签跨域访问资源。
是否同源的规则
同源需要满足相同的协议(scheme),相同的主机名(host),相同的端口号(port)
Compared URL | Outcome Reason |
---|---|
http://www.example.com/dir/page2.html | Success Same scheme, host and port |
http://www.example.com/dir2/other.html | Success Same scheme, host and port |
http://username:password@www.example.com/dir2/other.html | Success Same scheme, host and port |
http://www.example.com:81/dir/other.html | Failure Same scheme and host but different port |
https://www.example.com/dir/other.html | Failure Different scheme |
http://en.example.com/dir/other.html | Failure Different host |
http://example.com/dir/other.html | Failure Different host (exact match required) |
http://v2.www.example.com/dir/other.html | Failure Different host (exact match required) |
http://www.example.com:80/dir/other.html | Depends Port explicit. Depends on implementation in browser. |
::: tip
scheme: http https
:::
CORS存在的意义
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。
出于安全性,浏览器限制脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest 和 Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。
跨源域资源共享(CORS)机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。
CORS的工作原理是什么?
当浏览器发起跨域请求时,会在请求头中添加Origin字段,指示请求的源。服务器接收到请求后,会在响应头中添加Access-Control-Allow-Origin字段,指示允许访问的源。如果服务器允许该源访问资源,浏览器会将响应返回给客户端。
CORS中的预检请求是什么?为什么需要预检请求?
预检请求是浏览器在发送跨域请求前发送的一种OPTIONS请求,用于检查服务器是否支持跨域请求。预检请求中包含一些额外的头信息,如Access-Control-Request-Method、Access-Control-Request-Headers等。
预检请求的目的是确保服务器支持跨域请求,避免跨域请求对服务器造成安全风险。只有在服务器返回允许的响应头后,浏览器才会发送实际的跨域请求。
了解了上面的内容,我们解决浏览器控制台的跨域问题,一般有两个方向:
- 后端服务设置允许跨域访问
- 前端通过代理访问资源(开发阶段使用)
如何在服务器端配置CORS?
在服务器端配置CORS通常需要在响应头中添加一些字段,如Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等。通过配置这些字段,可以控制允许的源、请求方法和请求头。
用 Node.js 的一个框架 koa 来举例,解决跨域使用 koa-cors 非常简单,如下:
var koa = require('koa');
var route = require('koa-route');
var cors = require('koa-cors');
var app = koa();
app.use(cors());
app.use(route.get('/', function() {
this.body = { msg: 'Hello World!' };
}));
app.listen(3000);
这个中间件大概做了这样的事情:
module.exports = () => {
return async function(ctx, next) {
ctx.set('Content-Type', 'application/json');
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, PUT');
ctx.set('Access-Control-Allow-Headers', 'X-Requested-With, content-type, X-Authorization, X-uuid');
ctx.json = json.bind(ctx);
ctx.halt = halt.bind(ctx);
try {
await next();
} catch (e) {
return ctx.halt(e.code, e.message);
}
};
};
这样前端收到的响应会是下面的样子:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被 任意 外域访问。
前端代理
如果使用了webpack 那么配置一个代理就很容易,通过代理模拟出和服务端同源的请求。
//webpack.config.js
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
pathRewrite: { '^/api': '' },
},
},
},
};
这样前端发起的请求包含/api的路径就会被代理到 http://localhost:3000,并且会把/api替换为空。如果你的接口地址本来就包括/api,那只要把pathRewrite: { '^/api': '' }去掉即可。
这个devServer代理使用功能强大的 http-proxy-middleware 软件包。
http-proxy-middleware 内部又使用了 node-http-proxy
服务端代理
服务端代理是一种解决跨域访问的方法,通过在服务端发起请求并将结果返回给客户端,绕过了浏览器的同源策略限制。通常可以使用Node.js、Java、Python等后端语言来实现服务端代理。
以下是一个使用Node.js实现服务端代理的示例代码:
const express = require('express');
const request = require('request');
const app = express();
app.get('/proxy', (req, res) => {
const url = req.query.url;
request(url, (error, response, body) => {
if (!error && response.statusCode === 200) {
res.send(body);
} else {
res.status(500).send('Error');
}
});
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
在上面的示例中,当客户端发送请求到/proxy接口时,服务端会将请求转发到指定的URL,并将结果返回给客户端。
总结
总的来说,跨域资源共享是一个常见的Web开发问题,了解跨域资源共享的原理和解决方法对于开发安全可靠的Web应用程序非常重要。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。