当前位置: 首页 > news >正文

跨域的两种解决方法

解决跨域(CORS)问题主要有两类方案:通过服务器配置文件(Apache/Nginx)全局设置通过 PHP 代码动态设置。两种方案适用场景不同(服务器配置适合全局生效,PHP 适合代码层灵活控制),以下是具体实现:

一、通过 Apache 配置文件解决跨域

适合需要全局生效(所有 PHP 文件 / 接口都支持跨域)的场景,直接在 Apache 的虚拟主机配置或.htaccess中添加规则。

方式 1:修改 Apache 虚拟主机配置(推荐生产环境)

编辑 Apache 的虚拟主机配置文件(通常位于/etc/httpd/conf.d/域名.conf/etc/apache2/sites-available/域名.conf),添加以下配置:

apache

<VirtualHost *:80>ServerName your-domain.com  # 你的域名DocumentRoot /path/to/your/site  # 网站根目录(如TP6的public目录)# 跨域核心配置# 1. 匹配允许的源(支持多个域名,用正则匹配)SetEnvIf Origin "http(s)?://(.*\.bjtong\.com|crm\.bjceshi\.com)$" AccessControlAllowOrigin=$0# 2. 设置CORS响应头(always确保所有状态码都带跨域头,包括204、404等)Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOriginHeader always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"  # 允许的方法Header always set Access-Control-Allow-Headers "Content-Type, Token, X-Requested-With, Authorization"  # 允许的请求头Header always set Access-Control-Allow-Credentials "true"  # 允许携带凭证(cookie等)Header always set Access-Control-Max-Age "3600"  # 预检请求缓存时间(1小时)# 3. 处理预检请求(OPTIONS方法),直接返回204状态码<IfModule mod_rewrite.c>RewriteEngine OnRewriteCond %{REQUEST_METHOD} OPTIONSRewriteRule ^(.*)$ $1 [R=204,L]</IfModule>
</VirtualHost>

关键说明

  • SetEnvIf Origin:通过正则匹配允许的源(如*.bjtong.com),避免使用*(不安全,且不支持带凭证的跨域);
  • Header always setalways确保所有响应状态码(包括 204、403、500)都携带跨域头,解决 “部分状态码跨域失败” 问题;
  • 预检请求处理:OPTIONS方法是浏览器发送的跨域预检请求,直接返回 204(无内容)可减少不必要的资源消耗。
方式 2:通过.htaccess 文件配置(适合共享主机)

若没有服务器配置权限,可在网站根目录(如 TP6 的public目录)创建.htaccess文件,添加与虚拟主机配置相同的规则:

apache

# public/.htaccess
SetEnvIf Origin "http(s)?://(.*\.bjtong\.com|crm\.bjceshi\.com)$" AccessControlAllowOrigin=$0
Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Content-Type, Token, X-Requested-With, Authorization"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Max-Age "3600"<IfModule mod_rewrite.c>RewriteEngine OnRewriteCond %{REQUEST_METHOD} OPTIONSRewriteRule ^(.*)$ $1 [R=204,L]
</IfModule>

注意:需确保 Apache 启用了mod_headersmod_rewrite模块(可通过apachectl -M检查,未启用需执行a2enmod headers rewrite并重启 Apache)。

二、通过 Nginx 配置文件解决跨域

Nginx 的配置逻辑与 Apache 类似,但语法不同,需在serverlocation块中添加跨域规则。

编辑 Nginx 虚拟主机配置

打开 Nginx 的虚拟主机配置文件(通常位于/etc/nginx/conf.d/域名.conf/etc/nginx/sites-available/域名.conf),添加以下配置:

nginx

server {listen 80;server_name your-domain.com;  # 你的域名root /path/to/your/site;  # 网站根目录# 跨域核心配置location / {# 1. 允许的源(动态匹配请求的Origin,仅允许指定域名)set $allow_origin "";if ($http_origin ~* "^http(s)?://(.*\.bjtong\.com|crm\.bjceshi\.com)$") {set $allow_origin $http_origin;}# 2. 设置CORS响应头(always确保所有状态码生效)add_header Access-Control-Allow-Origin $allow_origin always;add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;add_header Access-Control-Allow-Headers "Content-Type, Token, X-Requested-With, Authorization" always;add_header Access-Control-Allow-Credentials "true" always;add_header Access-Control-Max-Age "3600" always;# 3. 处理预检请求(OPTIONS方法)if ($request_method = OPTIONS) {return 204;  # 直接返回204,无需响应体}# 其他配置(如PHP解析)try_files $uri $uri/ /index.php?$query_string;}# PHP解析配置(示例)location ~ \.php$ {fastcgi_pass 127.0.0.1:9000;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;include fastcgi_params;}
}

关键说明

  • set $allow_origin:通过if判断请求的Origin是否在允许列表,动态设置允许的源(避免*,支持带凭证跨域);
  • add_header ... alwaysalways参数确保 Nginx 对所有状态码(包括 404、500)都添加跨域头(Nginx 默认只对 200、204 等成功状态码添加头);
  • OPTIONS处理:直接返回 204,减少预检请求的处理成本。

配置完成后,执行nginx -t检查语法,无误后重启 Nginx:systemctl restart nginx

三、通过 PHP 代码直接设置跨域(灵活控制)

适合需要动态控制跨域规则(如根据用户角色、请求路径允许不同域名)的场景,直接在 PHP 脚本中通过header()函数设置响应头。

通用 PHP 跨域处理代码

在 PHP 脚本的最顶部(任何输出前)添加以下代码(可封装为函数或中间件):

<?php
// 1. 定义允许的源(根据实际需求修改)
$allowedOrigins = ['/^https?:\/\/(.*\.bjtong\.com)$/',    // 匹配所有bjtong.com子域'/^https?:\/\/(crm\.bjceshi\.com)$/'   // 精确匹配crm.bjceshi.com
];// 2. 获取请求的Origin头(浏览器发送的跨域源)
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
$allowOrigin = '';// 3. 验证Origin是否在允许列表中
foreach ($allowedOrigins as $pattern) {if (preg_match($pattern, $origin)) {$allowOrigin = $origin;break;}
}// 4. 设置CORS响应头(所有状态码都生效)
if (!empty($allowOrigin)) {header("Access-Control-Allow-Origin: {$allowOrigin}");
}
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Token, X-Requested-With, Authorization");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 3600");// 5. 处理预检请求(OPTIONS方法)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {http_response_code(204);  // 返回204无内容exit;  // 终止脚本,避免后续输出
}// 后续业务逻辑(示例)
// echo json_encode(['status' => 'success', 'data' => []]);
?>

如果是设置所有域名可访问,可直接如下简便设置:

<?php
header("Access-Control-Allow-Origin: *");  // 允许所有域名访问
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");  // 允许的方法
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept");  // 允许的头部信息
header("Access-Control-Allow-Credentials: true");  // 允许携带凭证信息
框架中使用(以 TP6 为例)

在 TP6 中,推荐将跨域逻辑封装为中间件(全局或路由级生效):

  1. 创建中间件app/middleware/Cors.php,内容同上(将代码放入handle方法);
  2. config/middleware.php中注册为全局中间件,或在路由中单独引用。

四、三种方法的对比与选择

方案优点缺点适用场景
Apache 配置全局生效,无需修改代码,性能好不支持动态规则,需服务器配置权限固定域名、全站点跨域需求
Nginx 配置全局生效,性能优于 PHP 代码,支持复杂规则配置语法较严格,需服务器权限高并发场景、固定跨域规则
PHP 代码设置支持动态规则(如数据库配置域名)需在每个脚本 / 中间件中调用,性能略低动态域名、按路径 / 角色区分跨域需求

关键注意事项

  1. 带凭证跨域:若前端需携带 cookie(withCredentials: true),Access-Control-Allow-Origin不能为*,必须指定具体域名;
  2. 预检请求OPTIONS方法是浏览器自动发送的,必须处理(返回 204 或 200),否则跨域请求会失败;
  3. 响应头一致性:确保Access-Control-Allow-Headers包含前端实际发送的请求头(如自定义的Token),否则会被浏览器拦截;
  4. HTTPS 兼容:规则中包含https?,同时支持 HTTP 和 HTTPS 环境。

根据项目的部署环境和跨域需求,选择合适的方案即可。

http://www.dtcms.com/a/391230.html

相关文章:

  • 小程序中获取年月日时分的组件
  • Redis热升级秘籍:零停机迁移方案与工具链
  • 时序数据库选型指南深度解析IoTDB架构设计与性能对比
  • springboot超市管理系统的设计与实现(代码+数据库+LW)
  • 让Trae写一个AI的api中继服务
  • 跨国制造业SD-WAN:延迟下降78%,运维成本下降53%
  • MySQL服务启动不成功的可能解决方法
  • 硬解码出现画面回退分析
  • P1068 [NOIP 2009 普及组] 分数线划定-普及-
  • 用python语言如何排大小
  • pycharm连接GitHub,怎么配置 SSH 密钥并改用 SSH 连接
  • ​​[硬件电路-265]:电源系统要考虑的因素包括:不同的输出电压、隔离防干扰、防反、防浪涌、电压可调、电源开关、电池、可充电、低纹波、低噪声、防波动等
  • 【开题答辩全过程】以 基于Python的电影推荐系统为例,包含答辩的问题和答案
  • 格拉姆角场(Gramian Angular Field, GAF)详解
  • 前端开发工具Vue有哪些?常用Vue前端开发工具推荐、Vue开发工具对比与最佳实践分享
  • 基于vue的幼儿园健康管理系统0fz0y(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 第69课 分类任务: 基于BERT训练情感分类与区别二分类本质思考
  • Mysql杂志(二十)——MyISAM索引结构与B树B+树
  • Java 大视界 -- 基于 Java 的大数据实时流处理在金融高频交易数据分析中的应用
  • BonkFun 推出 USD1:Meme 币玩法的新入口
  • flutter在包含ListVIew的滚动列表页面中监听手势
  • Redis 三种集群模式详解
  • 打开hot100
  • Ant-Design Table中使用 AStatisticCountdown倒计时,鼠标在表格上移动时倒计时被重置
  • Linux crontab 定时任务工具使用
  • 阿里云RDS mysql8数据本地恢复,与本地主从同步(容器中)
  • 记录一次mysql启动失败问题解决
  • LeetCode算法练习:35.搜索插入位置
  • (1) 为什么推荐tauri框架
  • 嵌入式面试高频(八)!!!C++语言(嵌入式八股文,嵌入式面经)