网站跨域问题解决方案(三种方法)

概述

跨域问题是前后端分离开发中最常见的障碍之一。浏览器出于安全考虑,默认禁止页面请求不同源(协议、域名、端口任一不同)的资源。本文整理了多种跨域解决方案,从服务端配置到开发调试,覆盖不同场景。

什么是跨域

当浏览器向一个不同源的 URL 发起请求时,就会触发跨域限制。同源必须满足三个条件完全一致:

  • 协议相同:http vs https 算不同源
  • 域名相同:www.example.com vs api.example.com 算不同源
  • 端口相同:8080 vs 8081 算不同源
注意:跨域限制是浏览器的行为,服务端之间的请求不受此限制。这也是很多解决方案的出发点。

方法一:升级 HTTPS(推荐首选)

将系统从 HTTP 升级到 HTTPS。现代浏览器对 HTTPS 站点的跨域策略更宽松,同时也是安全最佳实践。

具体步骤:

  1. 申请 SSL 证书(推荐 Let's Encrypt 免费证书)
  2. 在 Nginx/Apache 中配置证书
  3. 确保前端和后端都使用 HTTPS
  4. 将页面中的 HTTP 资源引用替换为 HTTPS 或协议相对路径

升级后,同协议下的跨域请求配合 CORS 头即可正常工作。

方法二:浏览器关闭安全检查(仅限开发调试)

  1. 浏览器打开 edge://flags/#local-network-access-check(Chrome 用 chrome://flags/#block-insecure-private-network-requests
  2. 找到 Local Network Access Checks(或 Block insecure private network requests),设置为 Disabled
  3. 重启浏览器
此方法仅适用于本地开发调试,绝不要在生产环境使用。建议开发时优先使用方法三(CORS 头),从根源解决问题。

方法三:服务端配置 CORS 跨域协议头(最常用)

在服务端响应中添加 CORS 头,告诉浏览器允许跨域访问。

各字段详解

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
Access-Control-Max-Age: 3600
Access-Control-Allow-Credentials: true
字段说明
Access-Control-Allow-Origin允许的源,* 表示所有。生产环境建议指定具体域名
Access-Control-Allow-Methods允许的 HTTP 方法
Access-Control-Allow-Headers允许的请求头,自定义头需要在此声明
Access-Control-Max-Age预检请求缓存时间(秒),减少 OPTIONS 请求次数
Access-Control-Allow-Credentials是否允许携带 Cookie,设为 true 时 Origin 不能为 *

Nginx 配置方式

location /api/ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
    add_header Access-Control-Allow-Headers "Content-Type, Authorization";

    if ($request_method = OPTIONS) {
        return 204;
    }

    proxy_pass http://127.0.0.1:8080;
}

Node.js / Express 配置

const cors = require("cors");
app.use(cors({
    origin: "https://www.your-site.com",
    methods: ["GET", "POST", "PUT", "DELETE"],
    credentials: true
}));

PHP 配置

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") {
    http_response_code(204);
    exit;
}

方法四:CORS 预检请求(OPTIONS)详解

对于非简单请求(如 Content-Type 为 application/json、自定义头、PUT/DELETE 方法),浏览器会先发送一个 OPTIONS 预检请求,询问服务端是否允许该跨域请求。服务端返回正确的 CORS 头后,浏览器才会发送真正的请求。

简单请求的条件:

  • 方法为 GET、HEAD、POST 之一
  • Content-Type 为 text/plain、multipart/form-data、application/x-www-form-urlencoded 之一
  • 无自定义请求头

不满足以上任一条件即为非简单请求,会触发预检。

方法五:JSONP(仅 GET,已过时)

利用 script 标签不受跨域限制的特性,动态创建 script 标签获取数据。仅支持 GET 请求。

// 前端
function jsonp(url, callback) {
    var script = document.createElement("script");
    script.src = url + "?callback=" + callback;
    document.body.appendChild(script);
}

// 后端返回 callback({"data": "hello"})
JSONP 存在安全风险(XSS),现代开发中已不推荐使用,建议用 CORS 替代。

方法六:服务端代理(反向代理)

在同源的服务端设置代理,将跨域请求转发到目标服务器。因为跨域限制只存在于浏览器,服务端之间的请求不受限。

// Nginx 反向代理示例
location /api/ {
    proxy_pass http://api.example.com/;  // 转发到真实 API
}

前端只需请求同源的 /api/xxx,Nginx 自动转发到目标,完美绕过跨域限制。

方法七:WebSocket

WebSocket 协议不受同源策略限制,可以在不同源之间建立全双工通信。适用于实时数据推送场景。

方案选择建议

场景推荐方案
前后端都是自己的服务Nginx 反向代理(方法六)
API 供第三方调用CORS 头(方法三)
本地开发调试浏览器关闭检查(方法二)或 CORS 允许 localhost
活字格服务端命令CORS 头 + Nginx 配置
实时推送WebSocket(方法七)

活字格中的跨域配置

活字格的服务端命令可以通过配置 CORS 头实现跨域调用:

location /Forguncy/ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    if ($request_method = OPTIONS) {
        return 204;
    }
    proxy_pass http://127.0.0.1:8081;
}

常见错误排查

错误信息原因解决
No Access-Control-Allow-Origin header服务端未返回 CORS 头添加 Access-Control-Allow-Origin
Credentials flag is true but origin is *携带 Cookie 但 Origin 为通配符指定具体 Origin 而非 *
Method PUT is not allowed未在 Allow-Methods 中声明该方法添加对应 HTTP 方法
Request header field xxx is not allowed自定义请求头未声明在 Allow-Headers 中添加

总结

  • 最推荐:Nginx 反向代理,同源访问,零跨域问题
  • 最通用:CORS 响应头,适合对外开放的 API
  • 开发调试:浏览器关闭安全检查,但别用在生产环境
  • 核心原理:跨域是浏览器限制,绕过思路是让浏览器以为同源,或者让服务端明确说我允许

标签: