xampp中localhost:80与localhost:8001因端口不同构成跨域,浏览器强制拦截;必须启用mod_headers模块、在directory块中配置header响应头并重启apache,不可依赖.htaccess或仅改端口绕过。

直接说结论:XAMPP 里用不同端口(比如 localhost:80 和 localhost:8001)访问,**本身就是跨域**,浏览器会拦截;不能靠“多端口”绕过 CORS,反而得主动配 CORS 或换方案。
为什么 localhost:80 和 localhost:8001 算跨域
同源策略看协议 + 域名 + 端口三者是否完全一致。http://localhost:80 和 http://localhost:8001 端口不同,就是跨域。这不是 XAMPP 的 bug,是浏览器强制行为。
- 常见误操作:开了两个端口,以为“都是 localhost 就没事”,结果 fetch 报
No 'Access-Control-Allow-Origin' header - Chrome 控制台 Network 里能看到请求发出去了,但 Response Headers 里没
Access-Control-Allow-Origin—— 说明服务端根本没回这个头 - 哪怕你只是想本地前后端分离调试(前端
:3000,后端:8001),也必须处理这个头
必须先启用 mod_headers 模块,否则 Header 指令无效
mod_headers 是 Apache 设置响应头的底层模块,XAMPP 默认不加载它。没这一步,后面所有 Header set 都白写。
XAMPP 8.0.30 是一款免费、开源的跨平台 Web 服务器集成包,专为快速搭建本地 PHP 开发环境而设计。该版本核心组件包括:Apache 2.4.56、MySQL 8.0.33、PHP 8.0.30、phpMyAdmin 5.2.1 等。它支持 Windows、Linux 和 macOS 系统,可让开发者在个人电脑上轻松模拟服务器环境,无需复杂配置即可运行 WordPress、Thin
- 打开
X:\xampp\apache\conf\httpd.conf - 搜索
mod_headers.so,取消这行注释:LoadModule headers_module modules/mod_headers.so - 改完必须重启 Apache,否则配置不生效
- 验证方式:访问
http://localhost/server-status(需先开mod_status)或直接看错误日志——如果模块没加载,Apache 启动时会报Invalid command 'Header'
在虚拟主机或 Directory 块里写 Header,别信 .htaccess
XAMPP 默认禁止 .htaccess 覆盖 Header 指令,放根目录下会导致 500 错误。必须写进主配置或虚拟主机定义里。
- 推荐在
httpd-vhosts.conf里配,比如为:8001单独建一个<virtualhost></virtualhost> - 在对应
<directory></directory>块内加:<directory> Options Indexes FollowSymLinks AllowOverride All Require all granted Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE" Header set Access-Control-Allow-Headers "Content-Type, X-Requested-With, Authorization" </directory> - 如果前端带
credentials: true,Access-Control-Allow-Origin不能用*,且必须加:Header set Access-Control-Allow-Credentials "true" -
Header add可用于允许多个域名,但注意顺序和覆盖逻辑;Header set后面的会覆盖前面的
OPTIONS 预检失败?不是 CORS 配错了,是方法没放开
非简单请求(如带 Content-Type: application/json)会先发一次 OPTIONS 请求,Apache 默认拒绝它,返回 405。
- 在同一个
<directory></directory>或<location></location>块里加:Require method GET POST HEAD OPTIONS - 或者更宽泛(仅开发):
Require all granted - 检查有没有
RewriteRule拦截了OPTIONS,比如某些伪静态规则写成RewriteCond %{REQUEST_FILENAME} !-f后直接重写,会把预检干掉 - 用
curl -X OPTIONS -I http://localhost:8001/api/test看响应状态码和头,确认是不是 405
最易被忽略的一点:改了配置但没重启 Apache,或者改的是错的配置文件(比如编辑了 httpd.conf 却在 httpd-vhosts.conf 里定义了虚拟主机,结果配置没生效)。每次改完,认准控制面板里「Restart」按钮点一下,再清浏览器缓存或用隐身窗口验证。










