1、什么是跨域

跨域是指一个域名下的资源去访问另一个域名下的资源。

2、什么是同源策略

同源策略是浏览器的一种安全机制,它要求发送请求的URL与服务器返回的URL必须具有相同的协议、主机和端口。

3、如何解决跨域问题

通过 Nginx 反向代理可以解决跨域问题,通常涉及设置 CORS 相关的响应头。以下是一个典型的 Nginx 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
location /myProject/api/ {

# 支持跨域的预检请求(OPTIONS 请求)
if ($request_method = 'OPTIONS') {
return 204; # 直接返回 204 No Content 作为响应
}

# 允许的跨域 Origin 设置为请求头中的 Origin
add_header 'Access-Control-Allow-Origin' "$http_origin" always;

# 设置跨域请求头
add_header 'Access-Control-Allow-Credentials' 'false' always;

# 支持的请求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;

# 支持的请求头
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type' always;

# 继续代理请求
proxy_pass http://localhost:9001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# 如果没有 Origin 头部,视为同源请求,允许通过
if ($http_origin = "") {
return;
}

# 如果请求头中有 Origin,且不在白名单内,则返回 403
if ($http_origin !~* "(http://www.test.com|http://10.14.32.138)") {
return 403;
}
}

解释:

  • Access-Control-Allow-Origin: 允许指定的域名进行跨域访问。通常通过 $http_origin 来动态获取请求头中的 Origin,或者直接指定具体的域名(如http://www.test.com)。
  • Access-Control-Allow-Credentials: 设置为 false 时,不允许发送 cookies 等凭证信息。
  • Access-Control-Allow-Methods: 指定允许的 HTTP 方法,如 GET, POST, OPTIONS
  • Access-Control-Allow-Headers: 指定允许的请求头,通常包括 Authorization, Content-Type 等常见头信息。

4、跨域常见场景

4.1 不同域名

  • example.com 访问 api.example.com
  • a.com 访问 b.com

4.2 不同端口

  • localhost:8080 访问 localhost:3000

4.3 不同协议

5.1 CORS(跨域资源共享)

CORS(Cross-Origin Resource Sharing)是一种允许浏览器向跨源服务器发出请求的机制。除了在 Nginx 中配置跨域,还可以在后端应用中设置 CORS 响应头,以控制跨域请求。

例如,在一个 Node.js 应用中,可以使用如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const express = require('express');
const app = express();

app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*"); // 允许所有域名访问
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization");
next();
});

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

app.listen(3000, () => console.log("Server is running on port 3000"));

在这个例子中,CORS 头部通过 res.header() 设置,允许所有域名(*)进行跨域访问,支持 GET, POST, PUT 等 HTTP 方法,并指定允许的请求头。

5.2 JSONP(JSON with Padding)

JSONP 是一种通过 <script> 标签来绕过同源策略进行跨域请求的方法。它的原理是利用 <script> 标签可以跨域加载 JavaScript 资源的特点,通过回调函数的方式返回数据。JSONP 只支持 GET 请求。

1
2
3
4
5
6
7
8
9
<script type="text/javascript">
function handleResponse(data) {
console.log(data);
}

var script = document.createElement('script');
script.src = 'http://example.com/api?callback=handleResponse';
document.body.appendChild(script);
</script>

5.3 WebSocket

WebSocket 允许在浏览器与服务器之间建立持久化的双向连接,这使得 WebSocket 成为一种天然的跨域解决方案。通过 WebSocket 协议,浏览器与不同域的服务器之间可以实时通信,且不受同源策略的限制。

5.4 后端代理

通过配置服务器端反向代理,将跨域请求转发到目标服务器。Nginx 和其他反向代理服务器可以帮助解决跨域问题。例如:

1
2
3
4
5
6
location /api/ {
proxy_pass http://api.example.com;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

在这个例子中,Nginx 会将 /api/ 开头的请求转发到 http://api.example.com,避免了跨域问题。