Nginx 实现跨域访问

跨域基础概念

一、什么是跨域

跨域是指由于浏览器的同源策略限制,不同域的页面之间无法直接访问各自的内容。

同源策略定义:必须满足“三同”条件才属于同源,即:

  • 同协议(如 http与https不同源)
  • 同域名(如 www.kk.com 与 www.oo.com 不同源)
  • 同端口(如 80 端口与 8080 端口不同源)

二、为什么需要跨域

浏览器的同源策略主要是为了防范 CSRF(跨站请求伪造)等安全攻击,但在实际开发中,经常需要跨域获取资源,例如:

  • 前端项目(www.kk.com)通过 Ajax 请求后端接口(www.oo.com/getuser/uid/220305)获取用户数据
  • 不同域名下的前后端分离项目进行数据交互

此时需要通过技术手段突破同源策略限制,实现合法的跨域访问。

跨域实现方式对比

实现方式 支持请求类型 适用场景 优缺点
JsonP(前后端结合) 仅支持 GET 请求 简单跨域数据获取 优点:实现简单;缺点:不支持 POST、安全性较低
CORS(纯后端) 支持 GET/POST/PUT/DELETE 等 大部分跨域场景 优点:标准方案、配置灵活;缺点:需后端单独配置
Nginx 代理(纯后端) 支持所有请求类型 生产环境推荐 优点:无需修改应用代码、统一管控、性能优;缺点:需配置 Nginx 服务器

注:JsonP 因局限性较强,本文不展开详细配置,如需了解可参考:https://blog.csdn.net/u014607184/article/details/52027879/

具体实现方案

一、CORS 方式(PHP 后端配置)

CORS 是 W3C 标准方案,通过在服务器端设置响应头 Access-Control-Allow-Origin 指定允许访问的域名,支持以下浏览器版本:

  • IE:8&9(需使用 XDomainRequest)、10+
  • Chrome:4+
  • Firefox:3.5+
  • Safari:4+
  • Opera:12+

1. 允许单个域名跨域

在 PHP 响应文件中直接设置响应头,示例代码:

<?php
// 允许 www.kk.com 跨域访问
header('Access-Control-Allow-Origin: http://www.kk.com');
$data = array(
    'name' => 'haveyb',
    'age'  => 26,
    'sex'  => 'man'
);
echo json_encode($data);

2. 允许多个域名跨域

通过判断请求来源域名,动态返回允许的 Origin 头,示例代码:

<?php
// 获取请求来源域名
$origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';

// 允许跨域的域名列表
$allow_origin = array(
    'http://www.kk.com',
    'http://www.gg.com'
);

// 验证请求域名是否在允许列表中
if (in_array($origin, $allow_origin)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

$data = array(
    'name' => 'haveyb',
    'age'  => 26,
    'sex'  => 'man'
);
echo json_encode($data);

 

二、Nginx 代理方式(推荐)

利用同源策略仅作用于浏览器端的特性,通过 Nginx 服务器转发跨域请求,无需修改应用代码,配置步骤如下:

1. 前端代码(www.kk.com)

正常发送 Ajax 请求,目标地址为需要跨域的接口,示例代码(使用 jQuery):

<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>测试 Ajax 跨域访问</title>
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
    $(document).ready(function(){
        $.ajax({
            type: "post", // 支持 POST 等所有请求类型
            url: "http://www.oo.com/1.php", // 跨域接口地址
            success: function(data) {
                alert(data); // 成功接收跨域数据
            },
            error: function() {
                alert("fail!!!,请刷新再试!");
            }
        });
    });
</script>
<body>
<h1>测试跨域访问</h1>
</body>
</html>

2. 后端代码(www.oo.com)

无需额外配置跨域头,正常返回数据即可,示例代码:

<?php
$data = array(
    'name' => 'haveyb',
    'age'  => 26,
    'sex'  => 'man'
);
echo json_encode($data);

3. Nginx 配置文件

在 Nginx 的 server 块中添加跨域相关配置,核心是通过 add_header 设置允许的 Origin 和请求方法:

server {
    listen       80;
    server_name  www.oo.com ; # 被跨域的域名
    root         "G:\oo"; # 项目根目录

    # 允许 www.kk.com 跨域访问
    add_header Access-Control-Allow-Origin http://www.kk.com;
    # 允许的请求方法
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

    # 默认首页配置
    location / {
        index  index.html index.htm index.php;
        # autoindex  on; # 可选,开启目录浏览
    }

    # PHP 解析配置
    location ~ \.php(.*)$ {
        fastcgi_pass   127.0.0.1:9000; # PHP-FPM 地址
        fastcgi_index  index.php;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO  $fastcgi_path_info;
        fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
        include        fastcgi_params; # 引入 fastcgi 配置
    }
}

4. 允许多个域名跨域(Nginx 进阶配置)

当需要允许多个域名跨域时,使用 Nginx 的 map 指令映射允许的域名列表,配置如下:

# 定义允许跨域的域名映射
map $http_origin $corsHost {
    default 0; # 默认不允许跨域
    "~http://www.kk.com" http://www.kk.com; # 允许的域名1
    "~http://www.gg.com" http://www.gg.com; # 允许的域名2
}

server {
    listen       80;
    server_name  www.oo.com ;
    root         "G:\oo";

    # 动态设置允许的 Origin
    add_header Access-Control-Allow-Origin $corsHost;
    # 允许的请求方法
    add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

    location / {
        index  index.html index.htm index.php;
    }

    location ~ \.php(.*)$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO  $fastcgi_path_info;
        fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
        include        fastcgi_params;
    }
}

注意事项

  1. 安全性考量:避免设置 Access-Control-Allow-Origin: *(允许所有域名跨域),仅开放必要的可信域名,降低安全风险。

  2. 请求方法支持Access-Control-Allow-Methods 需明确指定允许的请求类型,避免遗漏业务所需方法。

  3. Nginx 配置生效:修改 Nginx 配置后,需执行 nginx -t 验证配置正确性,再通过 nginx -s reload 重启 Nginx 使配置生效。

  4. 兼容性处理:针对 IE8/9 等低版本浏览器,若使用 CORS 方式需额外处理 XDomainRequest 对象,Nginx 代理方式无需额外兼容。

  5. 服务器负担:CORS 方式直接由应用服务器处理跨域逻辑,Nginx 代理方式通过反向代理转发请求,相比之下 Nginx 更擅长处理高并发,推荐生产环境使用。