本文目录导读:

在PHP项目中处理跨域请求,主要涉及设置正确的HTTP响应头,以下是几种常见的处理方法:
基础跨域设置
最简单的示例
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// 你的业务代码
echo json_encode(['message' => '跨域请求成功']);
?>
完整的生产环境配置
针对单个请求的处理
<?php
// 允许的域名
$allowedOrigins = [
'http://localhost:3000',
'https://yourdomain.com',
'https://*.yourdomain.com'
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// 检查来源域名
if (in_array($origin, $allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
}
// 处理预检请求 (OPTIONS)
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
header('Access-Control-Max-Age: 3600'); // 缓存预检请求结果1小时
header('Content-Type: text/plain charset=UTF-8');
header('Content-Length: 0');
http_response_code(204); // 无内容
exit;
}
// 其他HTTP方法继续处理
header('Content-Type: application/json; charset=utf-8');
// 你的业务逻辑
echo json_encode(['status' => 'success']);
?>
中间件方式(推荐)
创建一个CORS中间件类
<?php
class CorsMiddleware {
private $allowedOrigins = [];
private $allowedMethods = [];
private $allowedHeaders = [];
private $allowCredentials = false;
private $maxAge = 3600;
public function __construct(array $config = []) {
$this->allowedOrigins = $config['allowedOrigins'] ?? ['*'];
$this->allowedMethods = $config['allowedMethods'] ?? [
'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'
];
$this->allowedHeaders = $config['allowedHeaders'] ?? [
'Content-Type', 'Authorization', 'X-Requested-With'
];
$this->allowCredentials = $config['allowCredentials'] ?? false;
$this->maxAge = $config['maxAge'] ?? 3600;
}
public function handle() {
// 处理来源
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array('*', $this->allowedOrigins)) {
header('Access-Control-Allow-Origin: *');
} else if (in_array($origin, $this->allowedOrigins)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Vary: Origin'); // 通知缓存系统
}
// 设置其他CORS头
header('Access-Control-Allow-Methods: ' . implode(', ', $this->allowedMethods));
header('Access-Control-Allow-Headers: ' . implode(', ', $this->allowedHeaders));
if ($this->allowCredentials) {
header('Access-Control-Allow-Credentials: true');
}
// 处理预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Max-Age: ' . $this->maxAge);
http_response_code(204);
exit;
}
}
}
// 使用示例
$corsConfig = [
'allowedOrigins' => [
'http://localhost:3000',
'https://api.yourdomain.com'
],
'allowedMethods' => ['GET', 'POST', 'PUT', 'DELETE'],
'allowCredentials' => true,
];
$cors = new CorsMiddleware($corsConfig);
$cors->handle();
// 后续业务逻辑
?>
在框架中的处理
Laravel 示例
// app/Http/Middleware/Cors.php
namespace App\Http\Middleware;
use Closure;
class Cors
{
public function handle($request, Closure $next)
{
$response = $next($request);
$response->header('Access-Control-Allow-Origin', '*');
$response->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
$response->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
return $response;
}
}
// 在 kernel.php 中注册中间件
protected $middleware = [
// ...
\App\Http\Middleware\Cors::class,
];
使用 .htaccess 文件(Apache服务器)
<IfModule mod_headers.c>
# 允许所有来源
Header set Access-Control-Allow-Origin "*"
# 或者指定来源
# Header set Access-Control-Allow-Origin "http://yourdomain.com"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Header set Access-Control-Allow-Headers "Content-Type, Authorization"
# 处理 OPTIONS 预检请求
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
重要注意事项
安全建议
// 生产环境不要使用 *
// 应该指定具体的域名
header('Access-Control-Allow-Origin: https://specific-domain.com');
// 如果使用凭证(cookies)则不能使用 *
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Origin: https://specific-domain.com');
header('Vary: Origin'); // 重要:当使用动态Origin时需要设置
调试建议
// 开启错误显示
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// 日志记录
error_log('Origin: ' . ($_SERVER['HTTP_ORIGIN'] ?? 'none'));
error_log('Request Method: ' . $_SERVER['REQUEST_METHOD']);
最佳实践总结
- 明确限制来源:不要盲目使用 ,应该指定允许的具体域名
- 处理预检请求:对于复杂请求(自定义头等),正确处理 OPTIONS 请求
- 缓存预检结果:使用
Access-Control-Max-Age减少请求次数 - 安全凭证:如果需要传递 cookies,必须指定具体的来源域名
- 错误处理:当跨域失败时,确保返回适当的错误信息
选择合适的方案取决于你的项目需求和部署环境,对于简单的API,直接设置响应头即可;对于大型项目,建议使用中间件方式统一管理。