PHP跨域资源共享CORS配置
前后端分离架构中,跨域问题是必须处理的。CORS是浏览器允许跨域请求的机制。今天说说PHP中CORS的配置。
基础的CORS响应头。
```php
header('Access-Control-Allow-Origin: *');
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(204);
exit;
}
?>
带权限控制的CORS。
```php
class CorsMiddleware
{
private array $allowedOrigins;
private array $allowedMethods;
private array $allowedHeaders;
public function __construct(
array $allowedOrigins = ['*'],
array $allowedMethods = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
array $allowedHeaders = ['Content-Type', 'Authorization', 'X-Requested-With']
) {
$this->allowedOrigins = $allowedOrigins;
$this->allowedMethods = $allowedMethods;
$this->allowedHeaders = $allowedHeaders;
}
public function handle(): void
{
$origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
if (in_array('*', $this->allowedOrigins)) {
header('Access-Control-Allow-Origin: *');
} elseif (in_array($origin, $this->allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
header('Vary: Origin');
}
header('Access-Control-Allow-Methods: ' . implode(', ', $this->allowedMethods));
header('Access-Control-Allow-Headers: ' . implode(', ', $this->allowedHeaders));
header('Access-Control-Max-Age: 86400');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
}
public function addOrigin(string $origin): void
{
if (!in_array($origin, $this->allowedOrigins)) {
$this->allowedOrigins[] = $origin;
}
}
}
$cors = new CorsMiddleware(['http://localhost:3000', 'https://myapp.com']);
$cors->addOrigin('https://admin.myapp.com');
$cors->handle();
?>
处理凭证(Cookie)的CORS。
```php
header('Access-Control-Allow-Origin: https://myapp.com');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Content-Type');
// 使用凭证时,Access-Control-Allow-Origin不能是*
// 必须明确指定源
?>
自定义请求头的CORS。
```php
$allowedHeaders = ['Content-Type', 'Authorization', 'X-Custom-Header', 'X-Request-Id'];
header('Access-Control-Allow-Headers: ' . implode(', ', $allowedHeaders));
// 也可以在响应中暴露自定义头给前端
header('Access-Control-Expose-Headers: X-Total-Count, X-Request-Id');
?>
CORS中间件的完整实现。
```php
class CorsConfig
{
private static array $config = [
'allowed_origins' => ['*'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
'allowed_headers' => ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'],
'exposed_headers' => ['X-Total-Count', 'X-Request-Id'],
'max_age' => 86400,
'allow_credentials' => false,
];
public static function configure(array $config): void
{
self::$config = array_merge(self::$config, $config);
}
public static function apply(): void
{
$origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
if (self::$config['allow_credentials']) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Credentials: true');
} elseif (in_array('*', self::$config['allowed_origins'])) {
header('Access-Control-Allow-Origin: *');
} elseif (in_array($origin, self::$config['allowed_origins'])) {
header('Access-Control-Allow-Origin: ' . $origin);
}
header('Access-Control-Allow-Methods: ' . implode(', ', self::$config['allowed_methods']));
header('Access-Control-Allow-Headers: ' . implode(', ', self::$config['allowed_headers']));
if (!empty(self::$config['exposed_headers'])) {
header('Access-Control-Expose-Headers: ' . implode(', ', self::$config['exposed_headers']));
}
header('Access-Control-Max-Age: ' . self::$config['max_age']);
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
}
}
CorsConfig::configure([
'allowed_origins' => ['http://localhost:3000'],
'allow_credentials' => true,
]);
CorsConfig::apply();
?>
CORS是前后端分离必须处理的问题。开发环境可以宽放一些,生产环境要严格控制允许的源。使用凭证时Access-Control-Allow-Origin不能是*。OPTIONS预检请求要快速响应,不要做耗时操作。
PHP跨域资源共享CORS配置
张小明
前端开发工程师
Jupyter Notebook 新手避坑指南:从Server Error到无法运行代码,我踩过的雷都在这了
Jupyter Notebook 新手避坑指南:从Server Error到无法运行代码的完整解决方案第一次打开Jupyter Notebook时,那个简洁的交互式界面确实让人眼前一亮——直到你发现浏览器没有自动弹出,或者代码单元格突然拒绝执行。这些看似简单的工具&#x…
STM32F407裸机气体检测工程包:含启动文件、链接脚本、Makefile及完整编译输出
本文还有配套的精品资源,点击获取 简介:一套开箱即用的STM32F407VGTX裸机气体检测项目,不依赖HAL或RTOS,纯C语言实现。包含标准启动代码stm32_startup.c、系统调用适配syscalls.c、主控逻辑main.c,以及三套针对性链…
pandas多维聚合实战:银行级生产环境优化指南
1. 项目概述:为什么多维聚合不是“加个groupby”就能搞定的事我在银行风控部门做过三年数据管道开发,后来跳槽到一家头部支付机构做BI平台架构。这期间最常被业务方拍着桌子问的一句话是:“上个月华东区餐饮类商户的交易金额中位数、手续费波…
统计幻觉破除指南:从p值失真到探索成本量化
1. 这不是“相关不等于因果”的老生常谈,而是一场统计思维的底层重装你肯定听过那句被说烂了的话:“相关不等于因果”。但如果你以为这篇文章只是在重复这个常识,那就大错特错了。它真正要撬动的,是整个现代统计实践的地基——我们…
从硬件接线到程序调试:手把手教你用TIA Portal V17搞定S7-1200与第三方IO的Modbus通信
从硬件接线到程序调试:TIA Portal V17实现S7-1200与第三方IO的Modbus通信实战指南在工业自动化项目中,设备间的可靠通信是实现系统集成的关键环节。Modbus RTU作为一种成熟稳定的串行通信协议,广泛应用于PLC与各类IO设备的数据交互。本文将基…
避开这些坑!STM32驱动MFRC522读写M1卡(S50)的常见问题与调试心得
STM32与MFRC522读写M1卡实战:从硬件连接到软件调试的完整指南在物联网和智能设备快速发展的今天,非接触式IC卡技术已成为门禁系统、支付终端和身份识别等领域的重要组成部分。作为开发者,掌握STM32微控制器与MFRC522射频模块的协同工作方式&a…