本文目录导读:

在 PHP 中实现反向代理,通常有两种场景:
- 作为应用层代理:PHP 脚本接收请求后,通过
cURL或file_get_contents向目标服务器发起新的请求,再返回结果。 - 利用 Web 服务器功能:通过 Nginx 或 Apache 配置反向代理,PHP 本身不参与代理逻辑(性能最佳)。
下面分别说明两种实现方式,重点聚焦 PHP 代码实现反向代理。
纯 PHP 实现反向代理(适合小流量或特殊业务)
PHP 作为代理服务器,接收所有请求后转发给后端目标服务器。
基础示例(仅代理 GET 请求)
<?php
$targetUrl = 'http://192.168.1.100:8080'; // 目标服务器地址
// 获取当前请求的路径和查询参数
$path = $_SERVER['REQUEST_URI'];
$finalUrl = $targetUrl . $path;
// 初始化 cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $finalUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
// 转发请求头(可选)
$headers = getallheaders();
$curlHeaders = [];
foreach ($headers as $key => $value) {
$curlHeaders[] = "$key: $value";
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeaders);
// 执行请求
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 设置响应状态码
http_response_code($httpCode);
// 设置 Content-Type(若有)
// 这里简单范例不做解析,实际可以获取目标响应的 header
// 输出结果
echo $response;
完整的代理函数(支持 GET/POST/PUT/DELETE、请求体、自定义头)
<?php
function reverseProxy($targetBaseUrl) {
$url = $targetBaseUrl . $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
// 获取请求体
$body = file_get_contents('php://input');
// 获取客户端请求头
$headers = getallheaders();
$curlHeaders = [];
foreach ($headers as $key => $value) {
// 可过滤掉一些不宜转发的头(如 Host, Connection)
if (strtolower($key) !== 'host' && strtolower($key) !== 'connection') {
$curlHeaders[] = "$key: $value";
}
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeaders);
// 有请求体时发送
if ($body) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
// 获取响应头(如果需要转发响应头给客户端)
curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 分离响应头和响应体
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$responseHeader = substr($response, 0, $headerSize);
$responseBody = substr($response, $headerSize);
curl_close($ch);
// 设置 HTTP 状态码
http_response_code($httpCode);
// 转发响应头(可选)
$headerLines = explode("\r\n", $responseHeader);
foreach ($headerLines as $line) {
if (stripos($line, 'Transfer-Encoding') === false &&
stripos($line, 'Connection') === false) {
header($line, false);
}
}
echo $responseBody;
}
// 使用
reverseProxy('http://backend-server:8080');
注意事项:
- 纯 PHP 代理性能较差,每次请求都会消耗 PHP 进程来处理转发,不适合高并发。
- 需要处理 cookie、SSL、超时、连接池等问题。
- 建议配合 Web 服务器(如 Nginx 转发到 PHP-FPM)使用,而非直接监听外部端口。
使用 Web 服务器反向代理(推荐生产环境)
Nginx 配置示例
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8080; # 后端服务地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Apache 配置示例(需启用 mod_proxy)
<VirtualHost *:80>
ServerName example.com
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
PHP 在这种情况下无需任何代理代码,只负责处理业务逻辑。
使用 PHP 第三方库实现代理
如果非要纯 PHP 且想减少代码量,可使用 guzzlehttp/guzzle 配合中间件:
但最终原理仍是 cURL,只是封装了更多功能。
composer require guzzlehttp/guzzle
<?php use GuzzleHttp\Client; use GuzzleHttp\Psr7\Request; require 'vendor/autoload.php'; $client = new Client(['base_uri' => 'http://target-server/']); $request = new Request($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']); $response = $client->send($request); // 转发状态码和响应 http_response_code($response->getStatusCode()); echo $response->getBody();
| 方式 | 适用场景 | 性能 | 复杂度 |
|---|---|---|---|
| Web服务器反向代理 (Nginx/Apache) | 生产环境、高并发 | 极高 | 低(只需配置) |
| PHP cURL 代码代理 | 小流量、特殊业务(如需修改请求/响应) | 低 | 中 |
| PHP 框架/库代理 | 快速开发,已有 Guzzle 环境 | 低 | 中 |
建议:
- 大部分情况下使用 Nginx 反向代理。
- 只有当需要动态修改请求或响应内容、或无法修改 Web 服务器配置时,才考虑 PHP 代码实现代理。
如果需要在 PHP 中实现更完整的代理(支持 WebSocket、长连接、负载均衡等),请进一步说明你的具体需求,可以提供更定制化的方案。