Apache服务器如何实现根据UserAgent进行ProxyPass

要求

我们的web的某些页面,需要在SP View的情况下交给不同的后台应用处理。

举个例子。对于 www.example.com/demo, 我们希望,当用户用手机访问的访问的时候,我们交给backend, 当使用pc访问的话,我们照常访问在这个web服务器上的vhost下的www/example.com/demo

实现方法

我们用BrowserMatch来定义一个变量device,然后使用RewriteCond进行判断,最后用RewriteRule的P 选项进行反向代理。

1
2
3
4
5
6
7
8
BrowserMatch "^Mozilla/5\.0 \((iPhone;|iPod;|iPod touch;|Android .* Mobile)" device=smartphone
BrowserMatch "^Opera/.* Opera Mini" device=smartphone
BrowserMatch "^Mozilla/5\.0 \(Linux; U; Android .* (SC-01C|N-06D)" device=tablet

RewriteEngine On
RewriteCond %{ENV:device} ^smartphone$
#RewriteRule ^/demo/(.*)$ https://backend/$1 [P]
ProxyPassReverse ^/demo/(.*)$ https://backend/$1

Apache httpd ProxyPass 和 ProxyRemote

当我们的client无法直接access backend_server的时候,我们通常在webserver端有如下配置。

1
2
client->backend_server NG
client->webserver->backend_server OK
1
2
ProxyPass /example https://backend_server/example
ProxyPassReverse /example https://backend_server/example

这样,当client访问https://webserver/example的时候,我们获取到的其实就是backend_server/example的内容。

需要注意的是,从client的角度是无从得知这个内部的Forward的。因此用户访问https://webserver/example的时候,总是返回通常的200 response。

这点和用Redirect的Module是不一样的。

但是,如果当我们的webserver也无法直接访问backend_server的时候改怎么办呢?

答案是使用ProxyRemote

1
2
3
ProxyRemote https://backend_server/ https://proxy_server:port
ProxyPass /example https://backend_server/example
ProxyPassReverse /example https://backend_server/example

我们在设置ProxyPass之前事先指定哪些Forward的Request需要通过Proxy获取便可。

Apache rewriteRule 配合url 添加proxy header

问题描述

我们有类似 get /index.php -> https://backend.example.com/index.php 的需求。但是apache的DNS服务器并不知道backend。只知道它ip地址。所以我们这个时候需要添加Host header来访问backend。

`curl -H”backend.example.com” backend_ip_address/index.php”

那么配置该如何写呢?

解决方法

思路是使用RequestHeader添加host的header。然后使用RewriteRule来forword这个request。

1
2
3
RequestHeader set Host backend.example.com
ProxyPreserveHost On
RewriteRule ^\/index.php$ https://backend.example.com/index.php [p]

RequestHeader 和 Header 的区别?

RequestHeader 顾名思义是添加Request的header。 而Header是添加response的header。

ProxyPreserveHost 是什么意思?

我们修改了RequestHeader,但是默认这个RequestHeader 不会传给proxy。我们需要保持我们修改后的header然后传给backend.example.com

如何根据条件设置RequestHeader?

有时候,我们除了get /index.php需要forword,其他都是参考本地的静态文件,这个时候就不需要修改RequestHeader。所以我们需要根据条件判断是否添加header。
最简单的方法是使用apache的环境变量。

1
2
3
4
SetEnvIf REQUEST_URI "^\/index.php$" BACKEND=1
RequestHeader set Host backend.example.com ENV=BACKEND
ProxyPreserveHost On ENV=BACKEND
RewriteRule ^\/index.php$ https://backend.example.com/index.php [p]

以上。