一、apache转发客户端端口到tomcat的配置
做项目的时候需要获取客户端的ip以及端口。试了三种方式(下面贴了具体代码)都没办法去的客户端的端口,只能一步一步查原因了。我用第一第二种获取端口的方式拿到的都是null,第三种方式我拿到的客户端端口是0或者-1。登到公司服务器上,发现请求首先会到apache上,然后通过ajp协议转到tomcat。apache同时完成了反向代理。实现了在同一个域名下,apache会根据请求的地址,自动分配的各自的tomcat上。
这样看来很可能是apache转发的时候把客户的源端口丢失了。apache作为代理服务器,可以通过配置mod_rewrite 和 mod_headers这两个模块实现。
第一步,在apache配置文件中追加对上面两个module的引用,apache的配置文件httpd.conf:
- LoadModule rewrite_module modules/mod_rewrite.so
- LoadModule headers_module modules/mod_headers.so
(其实我自己这边服务器上的配置文件这里只是被注释掉了,去掉#就好了)
第二步,在apache配置文件中加上具体的rewrite规则
- RewriteEngine on
- RewriteRule .* - [E=REMOTE_PORT:%{REMOTE_PORT},NE]
- RequestHeader set X-Forwarded-SourcePort %{REMOTE_PORT}e
第一行是开启的意思
第二行是设置规则
第三行是添加属性
第三步,在每一个<VirtualHost>段里面加上这两行
- RewriteEngine On
- RewriteOptions Inherit
到第二步为止其实已经完成了转发端口用户的源端口,但是在我找资料的时候看见如果在apache上使用了虚拟主机,那还需要做第三步的操作,我这里一起整理了。
既然整理了,那我也顺便把我取源ip和端口的代码贴上来吧!
获取客户端源ip:
- //获取用户真实IP地址
- public String getUserIp(HttpServletRequest request){
- String[] sList = null;
- String sIp = null;
- sIp = request.getHeader("x-forwarded-for");
- if(sIp == null || sIp.length() == 0 || "unknown".equalsIgnoreCase(sIp)){
- sIp = request.getHeader("Proxy-Client-IP");
- }else{
- //如果通过了多级反向代理的话,取X-Forwarded-For中第一个非unknown的有效IP字符串
- sList = sIp.split(",");
- for(int i =0;i<sList.length;i++){
- if(sList[i]!= null && !"unknown".equalsIgnoreCase(sList[i])){
- sIp = sList[i];
- break;
- }
- }
- }
- if(sIp == null || sIp.length() == 0 || "unknown".equalsIgnoreCase(sIp)){
- sIp = request.getHeader("WL-Proxy-Client-IP");
- }
- if(sIp == null || sIp.length() == 0 || "unknown".equalsIgnoreCase(sIp)){
- sIp = request.getRemoteAddr();
- }
- return sIp;
- }
获取客户端源端口:
- //获取用户端口
- public String getUserPort(HttpServletRequest request){
- String sPort = null;
- //第一种
- // sPort = request.getHeader("remote_port");
- //第二种
- sPort = request.getHeader("X-Forwarded-SourcePort");
- //第三种
- // int port = request.getRemotePort();
- // sPort = String.valueOf(port);
- return sPort;
- }
其实走通这一步非常坎坷,开始我用了第一第二种方式获取端口的,但是都是null,后来用了第三种方式,获取到的客户端端口是0或者-1。那说明了这种方式是可行的,但是由于apache通过ajp协议的转发导致tomcat没拿到。所以,我的解决办法是现将ajp协议换成httpd协议,然后再修改apache配置(步骤一二三)。
后来在测试的时候跟项目日志和apache日志,我发现先直接请求tomcat得到的端口与通过apache转发获取的端口,两者我发现用差了很大。所以我又调整为第二种,其实是可以取到的,估计开始的时候我配置的不完整导致取不到这个属性。所以,最终我是通过获取apache配置的属性得到了客户端的源端口。
二、apache日志格式的配置
接下来介绍一下怎么在apache的日志信息里面加上客户端源ip和源端口。
apache日志信息的配置还是在httpd.conf文件里面。有两个基本指令,一个是日志路径CustomLog,还有一个是日志格式LogFormat
1、CustomLog日志路径
规则:CustomLog file|pipe format|nickname [env=[!]environment-variable]
1)file|pipe是符号“|”后面跟日志处理程序的路径(就像这样:| 日志处理程序路径)
2)format|nickname 日志的保存路径和命名规则
3)[env=[!]environment-variable],即[env=[!]服务器环境变量],它根据服务器上特定的环境变量是否被设置来决定是否对某一特定的请求进行日志记录。如果这个特定的环境变量被设置(或者在”env=!name”的情况下未被设置),那么这个请求将被记录
我的配置是这样的:
- CustomLog "|/opt/apache2.2/bin/rotatelogs /opt/apache2.2/logs/access_%Y_%m_%d_log 86400" common
2、LogFormat日志格式
规则:LogFormat “格式串” 日志格式名称
我需要在日志信息里面加上客户的源ip和端口,所以配置如下:
- LogFormat "%h %{REMOTE_PORT}e %l %u %t \"%r\" %>s %b" common
这里的%{REMOTE_PORT}e代表远端端口。他的原始格式是%{FOOBAR}e ,FOOBAR是环境变量的值。而环境器环境变量在mod_rewrite模块定义了下面表格里的属性
HTTP头 | 连接与请求 | |
---|---|---|
HTTP_USER_AGENT HTTP_REFERER HTTP_COOKIE HTTP_FORWARDED HTTP_HOST HTTP_PROXY_CONNECTION HTTP_ACCEPT | REMOTE_ADDR REMOTE_HOST REMOTE_PORT REMOTE_USER REMOTE_IDENT REQUEST_METHOD SCRIPT_FILENAME PATH_INFO QUERY_STRING AUTH_TYPE | |
服务器自身 | 日期和时间 | 其它 |
DOCUMENT_ROOT SERVER_ADMIN SERVER_NAME SERVER_ADDR SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE | TIME_YEAR TIME_MON TIME_DAY TIME_HOUR TIME_MIN TIME_SEC TIME_WDAY TIME | API_VERSION THE_REQUEST REQUEST_URI REQUEST_FILENAME IS_SUBREQ HTTPS |
apache的配置文件修改完以后要重启以后才会生效!!去日志目录下看日志,如果打印出来的是-,那就仔细检查吧,肯定少配了什么~~~
附上apache手册,以便参考!! 点击打开链接