Skip to content

跨域访问

约 722 字大约 2 分钟

前端

2024-8-20

浏览器特有的问题

在所处源的网站访问其他源的时候,浏览器出于安全考虑,会做出很多限制。这个叫做同源策略

同源的定义:协议 + 域名 + 端口

主要限制有以下:

  1. DOM 访问限制(不能读取和操作非同源的 DOM)
  2. Cookie 访问限制
  3. Ajax 响应数据限制(可以给非同源发送请求,接受到的数据未通过校验,不会移交给开发者)

注意:<iframe>元素可以放入页面,页面非同源时就不能操作元素了。

但是 <link><script><img>元素很可能跨域,但是浏览器通常对标签域不做处理,对开发几乎无影响。

CORS 跨域问题

Cross-origin Resource Sharing跨域资源共享,用于控制浏览器校验跨域请求的一套规范。

实际上浏览器能够收到非同源服务器返回的数据,但是浏览器的同源策略很可能不会将数据交出来。

通常解决方案就是处理 校验这一步,使得我们可以获取返回来的数据。

CORS 将请求分为了简单请求和复杂请求。具体区分自行去查阅,该文只做机制了解。

复杂请求在发送之前浏览器会自动发送一个预检请求,询问非同源服务器是否运行跨域请求。

预检请求:浏览器自动发送的一个 options请求,预检请求会包含以下特定的请求头:

(1) Origin

  • 作用:表示请求的来源(协议 + 域名 + 端口)。

(2) Access-Control-Request-Method

  • 作用:表示实际请求将使用的 HTTP 方法(如 GETPOST 等)。

(3) Access-Control-Request-Headers

  • 作用:表示实际请求中将包含的非简单请求头(如 AuthorizationContent-Type 等)。

(4) 其他标准请求头

预检请求还可能包含一些标准的请求头,例如:

  • Host:请求的目标主机。
  • User-Agent:浏览器的用户代理信息。
  • Accept:客户端接受的响应类型。

示例:

OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: http://client.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
Accept: */*
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://client.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true

cors 库

该库可以快速简便的设置响应预检请求的响应,解决跨域问题,只需要简单配置。

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

const app = express();

// 配置 CORS
app.use(cors({
    origin: 'http://client.example.com', // 允许的来源
    methods: ['GET', 'POST', 'PUT', 'DELETE'], // 允许的 HTTP 方法
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Custom-Header'], // 允许的请求头
}));

app.get('/data', (req, res) => {
    res.json({ message: 'This is a CORS-enabled response' });
});

app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000');
});