一、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手冊,以便參考!!點擊打開鏈接