本文目录导读:

在 PHP 中配置跨域 (CORS, Cross-Origin Resource Sharing),通常需要在服务端返回特定的 HTTP 响应头,以下是几种常见场景的配置方法。
核心响应头
// 最基本的3个响应头
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
简单跨域配置
<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json; charset=utf-8');
// 你的API逻辑
echo json_encode(['message' => 'Hello World']);
完整跨域配置(推荐)
<?php
// 允许访问的域名(生产环境建议指定具体域名)
$allowedOrigins = [
'http://localhost:3000',
'https://example.com',
];
// 获取请求来源
$origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
// 验证来源
if (in_array($origin, $allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true'); // 允许携带凭证(cookies)
}
// 设置允许的请求方法
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, PATCH');
// 设置允许的请求头
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
// 设置预检请求缓存时间(秒)
header('Access-Control-Max-Age: 86400');
// 处理预检请求 (OPTIONS)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// 你的API逻辑
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['status' => 'success']);
使用中间件模式
<?php
class CorsMiddleware {
public static function handle() {
// 允许的来源
$allowedOrigins = ['http://localhost:3000'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
}
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Max-Age: 86400');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
}
}
// 使用
CorsMiddleware::handle();
// 后续的API逻辑...
Nginx 代理配置(推荐用于生产)
有时候在 Nginx 层配置更灵活:
server {
listen 80;
server_name api.example.com;
location / {
# 允许跨域
add_header Access-Control-Allow-Origin * always;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
add_header Access-Control-Max-Age 86400;
# 处理OPTIONS请求
if ($request_method = 'OPTIONS') {
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
# 代理到PHP-FPM
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Apache .htaccess 配置
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
</IfModule>
# 处理OPTIONS请求
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
常见问题与解决
问题1:跨域请求带Cookie
header('Access-Control-Allow-Origin: https://specific-domain.com'); // 不能使用*
header('Access-Control-Allow-Credentials: true');
问题2:自定义请求头
// 客户端设置自定义头
headers: {
'X-Custom-Header': 'value'
}
// 服务端必须允许
header('Access-Control-Allow-Headers: X-Custom-Header');
问题3:文件上传跨域
header('Access-Control-Allow-Headers: Content-Type');
// 确保Content-Type被允许
问题4:多个域名支持
$allowedOrigins = [
'http://localhost:3000',
'https://example.com',
'https://subdomain.example.com'
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
} else {
header('Access-Control-Allow-Origin: ' . $allowedOrigins[0]);
}
安全建议
- *生产环境不要用 ``**,指定具体的域名
- 验证请求来源,避免恶意跨域
- 设置合理的
Access-Control-Max-Age,减少预检请求 - 只开放必要的请求方法(需要哪些就开放哪些)
- 敏感API需要结合其他认证措施(如JWT token)
选择哪种方式取决于你的项目架构和部署环境,对于简单项目,直接在PHP文件开头添加CORS头即可;对于大型项目推荐使用中间件模式或反向代理配置。