FrankenPHP 1.2 的 CORS 配置必须在 Caddyfile 中完成,因 PHP 的 header() 无效;需显式配置 header 指令、前置处理 OPTIONS 预检请求,并避免通配符与 credentials 共存。

FrankenPHP 1.2 的跨域配置不能靠 PHP 代码里的 header() 函数,因为它的底层是 Caddy,所有响应都经过 Caddy 中间件处理,PHP 层设置的头会被覆盖或忽略。必须在项目根目录的 Caddyfile 中显式声明 CORS 头,并提前处理 OPTIONS 预检请求。
必须在 Caddyfile 中配置 header 指令
Caddy 不识别 PHP 输出的跨域头,所以你要直接在 Caddyfile 里为不同路径加 header:
- /api/* 这类接口路径需完整支持复杂请求:指定允许的方法、头部、暴露字段
- / 根路径也要单独配,否则首页或静态资源加载时会因预检失败报 CORS 错误
- 不能写
header * { ... }—— Caddy 会报错:“wildcard not allowed in header directive”
必须前置响应 OPTIONS 请求
FrankenPHP 的 php_server 插件默认不处理 OPTIONS 方法,浏览器发来的预检请求会直接 404 或 500,根本进不了 PHP 层。
解决方法是在 php_server 之前添加匹配规则并返回 204:
立即学习“PHP免费学习笔记(深入)”;
- 用
@options method OPTIONS定义匹配器 - 用
respond @options 204 { ... }返回空响应并带上 CORS 头 - 确保这段配置出现在
php_server指令之前,否则不生效
注意 credentials 和通配符不能共存
如果前端用了 credentials: 'include'(比如带 Cookie 或 Authorization),后端就不能设 Access-Control-Allow-Origin: "*",否则浏览器直接拒绝响应。
此时必须:
- 把
Access-Control-Allow-Origin改成具体协议+域名,例如"https://myapp.com" - 同时加上
Access-Control-Allow-Credentials "true" - Caddy 不支持动态判断 Origin,多域名场景需配合反向代理或额外逻辑处理
一个可用的最小 Caddyfile 示例
假设服务跑在 localhost:8080,API 路径为 /api/:
localhost:8080 {
@options method OPTIONS
respond @options 204 {
header Access-Control-Allow-Origin "https://myapp.com"
header Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE"
header Access-Control-Allow-Headers "Content-Type,Authorization,X-Requested-With"
header Access-Control-Allow-Credentials "true"
}
<pre class="brush:php;toolbar:false;">header /api/* {
Access-Control-Allow-Origin "https://myapp.com"
Access-Control-Allow-Methods "GET,POST,OPTIONS,PUT,DELETE"
Access-Control-Allow-Headers "Content-Type,Authorization,X-Requested-With"
Access-Control-Expose-Headers "X-Total-Count"
Access-Control-Allow-Credentials "true"
}
header / {
Access-Control-Allow-Origin "https://myapp.com"
Access-Control-Allow-Credentials "true"
}
php_server}
改完记得重启 FrankenPHP,让 Caddyfile 重载生效。



















