什么是CORS?如何配置?

CORS(跨源资源共享)是一种基于HTTP头的机制,它允许服务器指示浏览器,允许某个源(域名、协议、端口)的Web应用访问自己服务器上的资源,从而绕过严格的同源策略限制。它是现代Web实现安全跨域请求的标准方案。

CORS的基本原理

当浏览器发现一个前端JavaScript发起的请求是跨域请求时(例如,从https://frontend.comhttps://api.backend.com发请求),它会自动在请求头中添加一个Origin字段,表明请求来自哪个源。

GET /api/data HTTP/1.1
Host: api.backend.com
Origin: https://frontend.com

服务器收到请求后,根据自身策略,在响应头中返回Access-Control-Allow-Origin,指明允许访问的来源。如果服务器允许该来源,浏览器就会放行,前端代码可以正常读取响应;否则,浏览器会拦截响应并抛出错误。

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.com

简单请求与预检请求

CORS将请求分为两类。简单请求(使用GET、HEAD、POST方法,且Content-Type为text/plainmultipart/form-dataapplication/x-www-form-urlencoded)会直接发出,服务器通过响应头控制是否允许。

对于非简单请求(如使用了PUT、DELETE方法,或Content-Type为application/json,或设置了自定义头),浏览器会先自动发送一个OPTIONS方法的预检请求

OPTIONS /api/data HTTP/1.1
Host: api.backend.com
Origin: https://frontend.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

服务器需要在预检请求的响应中明确允许将要使用的实际方法、头以及来源。

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: PUT, POST, GET
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400

只有预检请求通过后,浏览器才会发送真正的请求。

服务器端配置示例

服务器端的配置就是设置正确的响应头。以下是一个Node.js Express服务器的配置示例:

const express = require('express');
const app = express();

// 一个简单的CORS中间件
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'https://frontend.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  // 允许跨域请求携带Cookie(慎用)
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  // 处理预检请求
  if (req.method === 'OPTIONS') {
    return res.sendStatus(204);
  }
  next();
});

app.get('/api/data', (req, res) => {
  res.json({ data: 'Hello CORS' });
});

对于生产环境,通常使用成熟的中间件(如Express的cors包)来简化配置。Access-Control-Allow-Origin: *表示允许任何源访问,但这不能与Access-Control-Allow-Credentials: true(允许携带凭证如cookies)同时使用。

理解CORS是前后端分离开发的基础。前端开发者需要知道错误原因,而后端开发者必须正确配置响应头,两者协作才能实现安全的跨域数据交互。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

    暂无评论内容