最近在调试一个PHP项目时遇到了一个典型问题:访问.php页面时,浏览器直接显示源代码而不是渲染HTML内容。这种情况在开发API接口的站点中尤为常见,特别是当项目同时包含Web页面和API接口时。
通过curl命令检查响应头,发现返回的Content-Type被设置为application/json:
bash复制curl -I https://example.com/test.php
返回结果中关键信息:
code复制HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
这正是问题的根源所在。当服务器声明内容类型为JSON时,浏览器会按照纯文本处理响应体,即使实际内容是HTML标记。这与HTTP协议的工作机制直接相关:
提示:这个问题在混合型架构中特别容易发生,比如用同一套PHP代码同时服务Web页面和API接口时。
最直接的解决方案是在PHP文件顶部显式设置正确的Content-Type:
php复制<?php
header('Content-Type: text/html; charset=UTF-8');
// 后续HTML内容
?>
但这种方法有几个注意事项:
对于大型项目,更推荐在配置文件(config.php)中设置条件化的Content-Type:
php复制// config.php
if (!defined('API_MODE')) {
header('Content-Type: text/html; charset=UTF-8');
}
然后在API入口文件中定义:
php复制// api.php
define('API_MODE', true);
header('Content-Type: application/json');
这种方案的优点:
对于使用Web服务器的环境,还可以在服务器配置中强制覆盖:
Nginx配置示例:
nginx复制location ~ \.php$ {
add_header Content-Type text/html;
fastcgi_pass php-fpm;
}
Apache配置示例:
apache复制<FilesMatch "\.php$">
ForceType text/html
</FilesMatch>
当问题难以定位时,可以使用Burp Suite等代理工具检查原始响应:
powershell复制$env:HTTP_PROXY = "http://127.0.0.1:8080"
$env:HTTPS_PROXY = "http://127.0.0.1:8080"
powershell复制chcp 65001 > $null
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
对于混合型应用,推荐实现完整的内容协商:
php复制$accept = $_SERVER['HTTP_ACCEPT'] ?? '';
if (strpos($accept, 'application/json') !== false) {
header('Content-Type: application/json');
echo json_encode($data);
} else {
header('Content-Type: text/html');
include 'template.php';
}
确保全栈编码一致:
php复制new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", ...);
html复制<meta charset="UTF-8">
创建检测脚本定期验证关键页面的Content-Type:
php复制$testUrls = [
'/index.php',
'/api/user'
];
foreach ($testUrls as $url) {
$headers = get_headers('http://localhost'.$url);
$contentType = null;
foreach ($headers as $header) {
if (stripos($header, 'Content-Type') === 0) {
$contentType = $header;
break;
}
}
echo "$url: $contentType\n";
}
错误信息:
code复制Warning: Cannot modify header information - headers already sent
解决方案:
php复制ob_start();
// 业务逻辑
ob_end_flush();
可能原因:
排查方向:
我在实际项目中遇到过最棘手的情况是CDN缓存了错误的Content-Type,导致部分地区的用户始终看到源代码。解决方案是在CDN配置中设置"Cache-Control: no-store"头,并刷新所有缓存。