配置PHP跨域需在脚本开头使用header()设置CORS头,核心是Access-Control-Allow-Origin;应避免使用*,改为基于白名单动态允许指定源,同时处理OPTIONS预检请求并正确配置凭证传递。

配置PHP跨域请求,核心就是在服务器端通过PHP代码设置HTTP响应头,主要是
Access-Control-Allow-Origin
处理PHP跨域问题,最直接且常用的方法就是通过
header()
最简单粗暴的设置是允许所有来源访问:
<?php
// 允许所有来源访问
header("Access-Control-Allow-Origin: *");
// 允许的HTTP方法,例如GET, POST, PUT, DELETE, OPTIONS
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
// 允许的HTTP请求头,例如Content-Type, Authorization
header("Access-Control-Allow-Headers: Content-Type, Authorization");
// 允许发送Cookie等凭证信息
// 注意:当Access-Control-Allow-Origin不是*时,才允许设置为true
// header("Access-Control-Allow-Credentials: true");
// 如果是OPTIONS请求,直接返回204,因为OPTIONS请求只是预检,不需要实际内容
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit();
}
// 你的PHP业务逻辑代码
echo json_encode(['message' => 'Hello from PHP CORS!']);
?>然而,出于安全考虑,很少会直接使用
*
Origin
立即学习“PHP免费学习笔记(深入)”;
<?php
// 允许的域名白名单
$allowedOrigins = [
'http://localhost:3000',
'https://your-frontend-domain.com',
'http://127.0.0.1:8080' // 也可以包含IP地址和端口
];
// 获取请求的Origin头
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// 如果Origin在白名单中,则允许跨域
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: " . $origin);
// 允许发送Cookie等凭证信息,但Access-Control-Allow-Origin不能是*
header("Access-Control-Allow-Credentials: true");
} else {
// 如果不在白名单,可以不设置CORS头,或者设置一个默认的,但通常不设置更安全
// 这样做,浏览器会阻止非白名单的跨域请求
}
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Max-Age: 86400"); // 预检请求的缓存时间,单位秒
// 处理OPTIONS预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit();
}
// 你的PHP业务逻辑代码
echo json_encode(['data' => 'This is some data from the server.']);
?>说白了,跨域请求就是你的网页(比如
example.com
api.anothersite.com
那为什么会有这种限制呢?这其实是浏览器的一种安全策略,叫做“同源策略”(Same-Origin Policy)。你可以把它想象成一道防火墙,它的主要目的是为了保护用户的安全和隐私。如果没有同源策略,你访问一个恶意网站,它就可以通过JavaScript轻松地去请求你银行网站的API,获取你的个人信息,甚至执行转账操作。这简直是灾难性的。
所以,同源策略默认会阻止来自不同源的HTTP请求,除非服务器明确告知浏览器“我允许这个源来访问我”。这个“告知”的过程,就是我们配置CORS(Cross-Origin Resource Sharing)的工作。它不是为了为难开发者,而是为了构建一个更安全的网络环境。
Access-Control-Allow-Origin: *
当我看到有人在生产环境直接把
Access-Control-Allow-Origin
*
最大的风险在于安全漏洞。当你的API允许所有来源访问时,任何一个恶意网站都可以向你的API发送请求。如果你的API处理用户敏感数据(比如登录状态、个人信息、财务数据),或者执行一些有副作用的操作(比如删除数据、修改密码),那么恶意网站就可以利用用户的浏览器来发起这些请求。
具体来说,这可能导致:
Access-Control-Allow-Origin: *
所以,除非你的API确实是公开的,不涉及任何敏感数据,并且只提供静态内容,否则强烈建议指定具体的允许来源,而不是使用
*
动态设置允许的跨域来源是生产环境中更安全、更灵活的做法。它允许你维护一个白名单,只授权给信任的前端应用或服务。
核心思路是:
Origin
Origin
Origin
Access-Control-Allow-Origin
这是具体的PHP实现:
<?php
// 定义一个允许的域名白名单数组
$allowedOrigins = [
'http://localhost:3000', // 开发环境常用
'https://app.your-domain.com', // 你的生产前端应用
'https://staging.your-domain.com', // 你的预发布环境
'http://192.168.1.100:8080' // 内部测试IP或端口
];
// 从请求头中获取Origin,如果不存在则为空字符串
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// 检查请求的Origin是否在白名单中
if (in_array($origin, $allowedOrigins)) {
// 如果在白名单中,则允许该Origin访问
header("Access-Control-Allow-Origin: " . $origin);
// 如果你的前端需要发送Cookie或其他凭证,这个头是必须的
// 并且Access-Control-Allow-Origin不能是*
header("Access-Control-Allow-Credentials: true");
} else {
// 如果Origin不在白名单中,不设置Access-Control-Allow-Origin头
// 浏览器会自动阻止跨域请求,这是期望的安全行为
// 也可以选择返回一个特定的错误,但通常不设置头更简洁
}
// 允许的HTTP方法
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
// 允许的自定义请求头,例如用于认证的Authorization头
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
// 预检请求的缓存时间,单位秒。浏览器会在此时间内缓存预检结果,减少后续请求的预检开销
header("Access-Control-Max-Age: 86400"); // 24小时
// 处理OPTIONS预检请求
// 浏览器在发送非简单请求(如带有自定义头、PUT/DELETE方法等)之前,会先发送一个OPTIONS请求进行“预检”
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204); // 返回204 No Content表示成功处理预检
exit(); // 预检请求不需要返回实际内容
}
// 你的API业务逻辑代码
// 例如:
// $data = ['status' => 'success', 'message' => 'Data fetched successfully'];
// echo json_encode($data);
?>这段代码确保了只有你明确信任的域名才能成功进行跨域请求,大大提升了API的安全性。
OPTIONS预检请求是CORS机制中一个非常重要的环节,但很多新手可能会忽略它。简单来说,当浏览器判断一个跨域请求是“非简单请求”时,它不会直接发送实际的请求,而是会先发送一个HTTP OPTIONS请求到服务器,这就是所谓的“预检”。
什么时候会触发预检请求呢?
X-Custom-Header
Authorization
Content-Type
application/x-www-form-urlencoded
multipart/form-data
text/plain
application/json
预检请求的目的在于,在真正发送数据之前,先问问服务器:“嘿,我有个请求想发给你,用的是PUT方法,还带了个自定义头,你允许我这么做吗?”服务器收到OPTIONS请求后,需要通过响应头告诉浏览器它允许哪些方法、哪些头、以及是否允许携带凭证等。如果服务器的响应不符合浏览器的预期,或者没有正确的CORS头,浏览器就会直接拒绝实际的请求,并在控制台报错。
在PHP中处理OPTIONS预检请求,你需要:
$_SERVER['REQUEST_METHOD'] === 'OPTIONS'
Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
exit()
以下是一个处理OPTIONS预检请求的PHP示例:
<?php
// 允许的域名白名单,与前面解决方案中的白名单保持一致
$allowedOrigins = [
'http://localhost:3000',
'https://your-frontend-domain.com'
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: " . $origin);
header("Access-Control-Allow-Credentials: true");
} else {
// 非白名单来源,不设置CORS头,浏览器会阻止
}
// 无论是否白名单,这些方法和头通常是通用的
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With");
// 预检请求的缓存时间,单位秒。在缓存有效期内,浏览器不会重复发送OPTIONS请求
header("Access-Control-Max-Age: 86400"); // 24小时
// 核心:处理OPTIONS预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
// 返回204状态码,表示预检成功,无需返回内容
http_response_code(204);
exit(); // 终止脚本,不执行后续业务逻辑
}
// 你的实际业务逻辑代码从这里开始
// ...
echo json_encode(['message' => 'Actual data for ' . $_SERVER['REQUEST_METHOD'] . ' request.']);
?>正确处理OPTIONS预检请求是确保复杂跨域请求能够顺利进行的关键一步。
在跨域请求中,如果你需要前端携带Cookie、HTTP认证信息(如Basic Auth)或者客户端SSL证书等“凭证”信息,那么仅仅设置
Access-Control-Allow-Origin
服务器端(PHP)的配置:Access-Control-Allow-Credentials: true
当你的PHP后端需要接收前端发送的Cookie或认证头时,你必须在CORS响应头中明确告诉浏览器允许这样做。
<?php
// 假设你已经有了白名单判断逻辑
$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");
} else {
// ...
}
header("Access-Control-Allow-Methods: GET, POST, 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();
}
// 你的业务逻辑,现在可以访问 $_COOKIE 或 Authorization 头了
// 例如:
// if (isset($_COOKIE['session_id'])) {
// echo json_encode(['status' => 'logged_in', 'session' => $_COOKIE['session_id']]);
// } else {
// echo json_encode(['status' => 'not_logged_in']);
// }
?>重要注意事项:
Access-Control-Allow-Credentials
true
Access-Control-Allow-Origin
**。你必须指定一个具体的源(或动态匹配白名单中的某个源),否则浏览器会拒绝该请求。这是为了防止恶意网站通过
Access-Control-Allow-Credentials: true
客户端(前端JavaScript)的配置:withCredentials = true
仅仅后端设置还不够,前端的JavaScript代码也需要明确告知浏览器,这个跨域请求要携带凭证。
fetch
fetch('https://your-backend.com/api/data', {
method: 'GET',
credentials: 'include' // 关键点:设置为'include'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://your-backend.com/api/data', true);
xhr.withCredentials = true; // 关键点:设置为true
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(JSON.parse(xhr.responseText));
} else {
console.error('Error:', xhr.status, xhr.statusText);
}
};
xhr.onerror = function() {
console.error('Network error.');
};
xhr.send();如果前端没有设置
credentials: 'include'
withCredentials = true
Access-Control-Allow-Credentials: true
正确处理凭证对于需要用户认证和会话管理的跨域应用至关重要。务必确保前后端配置都到位,并始终牢记
Access-Control-Allow-Origin
*
以上就是PHP怎么配置跨域_PHP跨域请求设置教程的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号