使用PHP模仿Apache的ProxyPassReverse

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用PHP模仿Apache的ProxyPassReverse相关的知识,希望对你有一定的参考价值。

Problem Summary

Flow diagram with authenticated users viewing content from a localhost app.

假设您运行服务器并希望仅为已使用用户名和密码登录的用户(经过身份验证的用户)提供来自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标头未被修改。

例如:

要了解失败的原因,请参阅下面正确运行的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的主要内容,如果未能解决你的问题,请参考以下文章

用 node.js 模仿 Apache 的部分功能

Node.js之模仿Apache访问指定目录下的资源

Laravel php artisan 服务于模仿 HTTPS

C#时间转整型(时间戳),模仿php strtotime函数的部分功能

php 留下模仿按钮

php 模仿图标