什么是CORS(跨源资源共享)?

CORS(Cross-Origin Resource Sharing)是一种机制,容许网页从不同的域拜访服务器上的资源。

在同源策略下,浏览器限度了跨域拜访,CORS容许服务器指定哪些源能够拜访其资源。

同源策略(Same-origin policy)

同源策略在web利用平安模型中是一个重要的概念。在这个策略下,浏览器容许第一个网页中蕴含的脚本能够获取第二个网页的数据,前提是这两个网页在同一个源下。

同源:须要URI、主机名、端口都雷同。

这个策略能够避免一个网页上的歹意脚本通过DOM获取其余网页的敏感数据。

须要牢记的一点就是同源策略只利用于脚本,这意味着像images、css和其余动静加载的脚本 能够通过对应的标签跨域拜访资源。

是否同源的规定

同源须要满足雷同的协定(scheme),雷同的主机名(host),雷同的端口号(port)

Compared URLOutcome Reason
http://www.example.com/dir/page2.htmlSuccess Same scheme, host and port
http://www.example.com/dir2/other.htmlSuccess Same scheme, host and port
http://username:password@www.example.com/dir2/other.htmlSuccess Same scheme, host and port
http://www.example.com:81/dir/other.htmlFailure Same scheme and host but different port
https://www.example.com/dir/other.htmlFailure Different scheme
http://en.example.com/dir/other.htmlFailure Different host
http://example.com/dir/other.htmlFailure Different host (exact match required)
http://v2.www.example.com/dir/other.htmlFailure Different host (exact match required)
http://www.example.com:80/dir/other.htmlDepends 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等。

预检申请的目标是确保服务器反对跨域申请,防止跨域申请对服务器造成平安危险。只有在服务器返回容许的响应头后,浏览器才会发送理论的跨域申请。

理解了下面的内容,咱们解决浏览器控制台的跨域问题,个别有两个方向:

  1. 后端服务设置容许跨域拜访
  2. 前端通过代理拜访资源(开发阶段应用)

如何在服务器端配置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 OKDate: Mon, 01 Dec 2008 00:23:53 GMTServer: Apache/2Access-Control-Allow-Origin: *Keep-Alive: timeout=2, max=100Connection: Keep-AliveTransfer-Encoding: chunkedContent-Type: application/xml

本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源能够被 任意 外域拜访。

前端代理

如果应用了webpack 那么配置一个代理就很容易,通过代理模拟出和服务端同源的申请。

//webpack.config.jsmodule.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应用程序十分重要。

参考链接

跨源资源共享(CORS)