FrankenPHP 正确服务 Symfony 前后端需用 Caddyfile 显式分流:前端静态资源(dist/)通过 try_files 优先返回,API 路径(如 /api/*)明确 php_server 转发,SPA fallback 补 index.html;worker 模式须改用 symfony/runtime 入口并注入环境变量;HTTPS 需正确配置 SERVER_NAME、DNS 和持久化 /data 卷;跨域需绑定 0.0.0.0 并显式设 CORS 头。

如何让 FrankenPHP 正确服务 Symfony 前端静态资源与后端 API
FrankenPHP 默认把 public/ 当作根目录,但前后端分离项目常把前端构建产物(如 Vue/React 的 dist/)放在独立路径,而 Symfony API 仍走 /api/ 或 /。若不显式区分,Caddy 的路由规则会把所有请求都交给 PHP 处理,导致静态文件 404 或 API 被错误重写。
核心是用 Caddyfile 的 handle + try_files 显式分流:
- 前端静态文件(
/下的 HTML/JS/CSS)优先匹配dist/目录,命中则直接返回,不进 PHP - API 请求(如
/api/、/login)必须明确转发给 Symfony 的index.php,否则路由失效 - SPA 的 fallback(如 Vue Router 的
history模式)需在静态规则末尾加try_files {path} /index.html
示例 Caddyfile 片段:
your-domain.com {
root * /app/dist
# 前端静态资源:先找文件,再 fallback 到 index.html
handle {
try_files {path} {path}/ /index.html
}
<pre class="brush:php;toolbar:false;"># 后端 API:只匹配 /api/* 和 /login 等显式路径,转给 Symfony
handle /api/* /login /logout {
php_server
}
# 兜底:其他未匹配路径(如 /admin)也走 PHP,避免 404
handle {
php_server
}}
启用 worker 模式时 Symfony 容器初始化失败怎么办
worker 模式下,Symfony 容器在进程启动时初始化一次,之后复用。但默认的 Kernel::boot() 依赖每次请求的 $request 对象,而 worker 进程启动时没有真实请求上下文,直接调用会报 Request stack is empty 或 Environment variable not found。
必须改用 FrankenPHP 官方推荐的 SymfonyRuntime 启动方式,并确保 public/index.php 使用 frankenphp 兼容入口:
- 确认已安装
symfony/runtime包:composer require symfony/runtime -
public/index.php必须以Runtime::get()->getRunner(...)开头,不能手动 new Kernel - 环境变量(如
APP_ENV)需通过ENV文件或 Dockerenvironment注入,不能依赖 .env 本地加载(worker 进程不重读) - 禁用开发模式下的调试工具(如 WebProfilerBundle),它在常驻进程中可能引发内存泄漏
HTTPS 自动续期失败或证书不生效的常见配置点
FrankenPHP 内置 Caddy 的自动 HTTPS,但前后端分离项目容易因域名配置或 DNS 延迟导致 acme: error 或证书为自签名。
-
SERVER_NAME环境变量必须设为完整域名(如api.example.com),不能是localhost或 IP;裸域名(example.com)和 www(www.example.com)需分别申请或配置通配符 - DNS A 记录必须提前生效,Let’s Encrypt 会做实时验证;若用 Cloudflare,需关闭代理(DNS only 模式),否则验证请求被拦截
- Caddy 的证书存储路径(
/data)必须持久化,Docker 中要用 volume 挂载,否则重启后证书丢失,触发新申请限频 - 首次启动时若网络不通,Caddy 可能静默降级为自签名证书;检查日志中是否有
obtain certificate成功字样,而非using self-signed
为什么 php-server 命令启动后前端白屏、API 返回 500
这不是代码问题,而是 FrankenPHP 的默认行为:它只监听 127.0.0.1:8000,且不自动启用 CORS。前后端分离下,前端运行在 http://localhost:5173,浏览器发起的跨域请求会被拒绝,返回空响应或预检失败。
- 启动时必须显式绑定到
0.0.0.0:frankenphp php-server --host 0.0.0.0:8000 - 在 Caddyfile 中添加 CORS 头(尤其开发阶段):
header Access-Control-Allow-Origin "*",生产环境应限定具体域名 - Symfony 的
nelmio/cors-bundle在 worker 模式下需额外配置allow_origin为数组,单字符串不生效 - 检查
phpinfo()输出中$_SERVER['REQUEST_URI']是否含多余前缀(如被 Nginx 重写过),FrankenPHP 下该值应为原始路径
worker 模式省掉框架引导开销是实打实的,但它的代价是——你不能再把“每次请求都是干净沙盒”当作默认假设。环境变量、全局状态、数据库连接池、甚至 OPcache 的脚本缓存,都会跨请求延续。没意识到这点,就容易在压测时看到内存缓慢上涨或 session 错乱。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











