使用PHP模仿Apache的ProxyPassReverse
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用PHP模仿Apache的ProxyPassReverse相关的知识,希望对你有一定的参考价值。
Problem Summary
假设您运行服务器并希望仅为已使用用户名和密码登录的用户(经过身份验证的用户)提供来自localhost应用程序的内容。
该应用程序在您的服务器上运行,但不会向公众公开。它只能通过服务器上的http://localhost:3838获得。
为简单起见,假设您运行localhost应用程序的方式如下:
cd my-private-folder
python3 -m http.server 3838
经过身份验证的用户应该能够访问http://example.com/app以查看localhost应用程序提供的内容。
应拒绝未经身份验证的用户访问并重定向到登录页面。
Questions
- Apache有一个指令
ProxyPass
,它在请求发送到目标之前修改请求中的HTTP头。它还有一个指令ProxyPassReverse
,它在响应返回给用户之前修改响应中的标头。 - 有没有办法模仿Apache在php中的行为?
- 使用Laravel PHP框架有一个简单的方法吗?
作为参考,有一个名为oxy的包在Go中实现了这个目标。我不知道PHP的等效包。
Failed attempt 1: Using routes
这是我用Laravel 5.5尝试的:
# /var/www/example.com/routes/web.php
Route::get('/app', function() {
return Response::make(
file_get_contents("http://localhost:3838/")
);
});
# This does not work, because the HTTP header is not modified.
Route::get('/app/{any}', function($any) {
return Response::make(
file_get_contents("http://localhost:3838/$any")
);
})->where('any', '.*');
这成功地将内容从localhost:3838
传递到example.com/app
,但它无法传递应用程序请求的任何资源,因为HTTP标头未被修改。
例如:
- localhost应用程序使用javascript来请求
/resource.jpg
- 我希望资源从http://localhost:3838/resource.jpg传递到http://example.com/app/resource.jpg
- 相反,该应用程序发出失败的请求获取http://example.com/resource.jpg
要了解失败的原因,请参阅下面正确运行的Apache解决方案。 Apache有一个名为ProxyPassReverse的指令,用于修改HTTP标头,因此localhost应用程序从正确的URL请求资源。
Using Apache
Apache运行完美!但是,添加新用户需要在服务器上运行htpasswd
命令。
使用Laravel,新用户应该能够在网站上自行注册。
如果没有Laravel,您可以使用Apache来保护应用程序,如下所示:
# /etc/apache2/sites-available/example.com.conf
<VirtualHost *:80>
ServerName example.com
Redirect /app /app/
ProxyPass /app/ http://localhost:3838/
ProxyPassReverse /app/ http://localhost:3838/
ProxyPreserveHost On
<Location /app/>
AuthType Basic
AuthName "Restricted Access - Please Authenticate"
AuthUserFile /etc/httpd/htpasswd.users
Require user myusername
# To add a new user: htpasswd /etc/httpd/htpasswd.users newuser
</Location>
</VirtualHost>
这个相关的答案帮助我更好地理解ProxyPassReverse
指令的工作原理:
如果问题仅与资产有关,您可以将它们路由到localhost:3838
应用程序:
# /var/www/example.com/routes/web.php
Route::get('/app/{any}', function($any) {
return Response::make(
file_get_contents("http://localhost:3838/$any")
);
})->where('any', '.*');
Route::get('/{assets}', function($assets) {
return Response::make(
file_get_contents("http://localhost:3838/$assets")
);
})->where('assets', '.*(png|jpe?g|js)');
我认为Jens Segers有一个软件包可以让PHP模仿ProxyPass
指令:https://github.com/jenssegers/php-proxy
以下是GitHub自述文件中的一个示例:
use ProxyProxy;
use ProxyAdapterGuzzleGuzzleAdapter;
use ProxyFilterRemoveEncodingFilter;
use ZendDiactorosServerRequestFactory;
// Create a PSR7 request based on the current browser request.
$request = ServerRequestFactory::fromGlobals();
// Create a guzzle client
$guzzle = new GuzzleHttpClient();
// Create the proxy instance
$proxy = new Proxy(new GuzzleAdapter($guzzle));
// Add a response filter that removes the encoding headers.
$proxy->filter(new RemoveEncodingFilter());
// Forward the request and get the response.
$response = $proxy->forward($request)->to('http://example.com');
// Output response to the browser.
(new ZendDiactorosResponseSapiEmitter)->emit($response);
以上是关于使用PHP模仿Apache的ProxyPassReverse的主要内容,如果未能解决你的问题,请参考以下文章
Laravel php artisan 服务于模仿 HTTPS