開發過web應用的人,應該都知道http重定向這個功能,html就有最簡單的方法:
<meta http-equiv="refresh" content="5;url=http://www.cppblog.com/cool-liangbing/">,
也就是告訴你的瀏覽器5秒之后自動跳轉到我的c++博客首頁http://www.cppblog.com/cool-liangbing/。
重定向常常用于自動跳轉,從活動空間來看大概分兩類:服務器內部跳轉和服務器之間跳轉。
服務器內部跳轉常見于“登陸成功!5秒之后將自動進入首頁”這種應用。而服務器之間跳轉,種類稍微
多一些:(1)從服務器內跳往外部服務器; (2)從A服務器跳轉到B服務器,接著跳轉到C服務器;
(3) 從A服務器跳轉到B服務器, 業務處理完畢之后又跳轉到A服務器; (4) 從用戶瀏覽器向A服務器
發送請求,在出口網關處進行重定向,如通過iptable之類,重定向到一個認證服務器B,返回一個
認證登陸的頁面,當用戶輸入了正確的用戶名和密碼等,認證服務器B再通過http重定向到A服務器.
以上所說的4種模式,前3種不值一提,而第4種則有些問題,不是那么容易跳轉成功的。
不管你的認證服務器B是用現在的tomcat還是resin,或者其它流行的web服務器,最后發現總是
不能從認證服務器B跳到A服務器. 剛開始懷疑html那種方法不行,就改用javascript寫法,改用jsp調用
方法,甚至直接在servlet里調用重定向接口,一一試遍,都失敗了,這才懷疑可能不是程序寫法上
的問題。
在萬般無奈情況下,使用CommView工具來抓包看看,從tcp包本身、http request和http response
包內容來看,看不出什么不對。但發現整個跳轉只在一個tcp連接上進行,這使我想到iptable把向A服務器
的請求偷偷轉發到認證服務器B, 而瀏覽器還認為認證服務器B就是A服務器, 所以只要這條tcp連接不斷,
瀏覽器就一直認為這種映射關系正確,所以你怎么也跳轉不到真正的目的地-A服務器.
但是我們用老版本httpd或thttpd做web服務器,則可以正常跳轉,何故?http協議版本差別:
老版本httpd或thttpd采用http1.0協議,而tomcat和resin這些jsp容器最新版本,大都已經實現了http1.1
協議了,對我們這個問題就是connection是采用非持久的還是持久模式,提取兩個版本協議說明:
(1) http1.0:
原文:Except for experimental applications, current practice requires that
the connection be established by the client prior to each request and
closed by the server after sending the response.
翻譯:實驗室應用除外,當前的做法是客戶端在每次請求之前建立連接,而服務器端在發送回應后關閉此連接。
(2) http1.1:
原文:In HTTP/1.0, most implementations used a new connection for each request/response exchange.
In HTTP/1.1, a connection may be used for one or more request/response exchanges,
although connections may be closed for a variety of reasons (see section 8.1).
翻譯:在HTTP/1.0協議下,大多數HTTP服務器實現對每一個請求/應答使用一個新連接. 而在HTTP/1.1協議下,一個或多個請求/應答使用同一個連接。
(section 8.1詳細說明了為什么這么做)
從協議上分析清楚之后,我們怎么解決上面那個現實問題?肯定不能使用http1.1這種持久性連接。
查了下tomcat docment說明,默認實現了http1.1,現在版本的connector已經早不提供http1.0支持了,
難道我們要退回到http1.0的版本?那是多么痛苦的事情。再查查tomcat/conf/server.xml里關于connector
的配置,有一個參數connecttimeout,默認是20000ms, 作為服務器不可能爭對socket accept()的,應該是
socket recv()的超時,那么我們設置它為比我們<meta http-equiv="refresh" content="5;url=xxx">里
秒數小就可以了,保證在跳轉之前以前的tcp連接被tomcat服務器斷開就可以了,當然iptable應該在認證成功
之后不再對這個上網用戶發出的http請求重定向到認證服務器, 這個很容易做到,暫不提細節。
最后附上UML圖以方便理解:
<meta http-equiv="refresh" content="5;url=http://www.cppblog.com/cool-liangbing/">,
也就是告訴你的瀏覽器5秒之后自動跳轉到我的c++博客首頁http://www.cppblog.com/cool-liangbing/。
重定向常常用于自動跳轉,從活動空間來看大概分兩類:服務器內部跳轉和服務器之間跳轉。
服務器內部跳轉常見于“登陸成功!5秒之后將自動進入首頁”這種應用。而服務器之間跳轉,種類稍微
多一些:(1)從服務器內跳往外部服務器; (2)從A服務器跳轉到B服務器,接著跳轉到C服務器;
(3) 從A服務器跳轉到B服務器, 業務處理完畢之后又跳轉到A服務器; (4) 從用戶瀏覽器向A服務器
發送請求,在出口網關處進行重定向,如通過iptable之類,重定向到一個認證服務器B,返回一個
認證登陸的頁面,當用戶輸入了正確的用戶名和密碼等,認證服務器B再通過http重定向到A服務器.
以上所說的4種模式,前3種不值一提,而第4種則有些問題,不是那么容易跳轉成功的。
不管你的認證服務器B是用現在的tomcat還是resin,或者其它流行的web服務器,最后發現總是
不能從認證服務器B跳到A服務器. 剛開始懷疑html那種方法不行,就改用javascript寫法,改用jsp調用
方法,甚至直接在servlet里調用重定向接口,一一試遍,都失敗了,這才懷疑可能不是程序寫法上
的問題。
在萬般無奈情況下,使用CommView工具來抓包看看,從tcp包本身、http request和http response
包內容來看,看不出什么不對。但發現整個跳轉只在一個tcp連接上進行,這使我想到iptable把向A服務器
的請求偷偷轉發到認證服務器B, 而瀏覽器還認為認證服務器B就是A服務器, 所以只要這條tcp連接不斷,
瀏覽器就一直認為這種映射關系正確,所以你怎么也跳轉不到真正的目的地-A服務器.
但是我們用老版本httpd或thttpd做web服務器,則可以正常跳轉,何故?http協議版本差別:
老版本httpd或thttpd采用http1.0協議,而tomcat和resin這些jsp容器最新版本,大都已經實現了http1.1
協議了,對我們這個問題就是connection是采用非持久的還是持久模式,提取兩個版本協議說明:
(1) http1.0:
原文:Except for experimental applications, current practice requires that
the connection be established by the client prior to each request and
closed by the server after sending the response.
翻譯:實驗室應用除外,當前的做法是客戶端在每次請求之前建立連接,而服務器端在發送回應后關閉此連接。
(2) http1.1:
原文:In HTTP/1.0, most implementations used a new connection for each request/response exchange.
In HTTP/1.1, a connection may be used for one or more request/response exchanges,
although connections may be closed for a variety of reasons (see section 8.1).
翻譯:在HTTP/1.0協議下,大多數HTTP服務器實現對每一個請求/應答使用一個新連接. 而在HTTP/1.1協議下,一個或多個請求/應答使用同一個連接。
(section 8.1詳細說明了為什么這么做)
從協議上分析清楚之后,我們怎么解決上面那個現實問題?肯定不能使用http1.1這種持久性連接。
查了下tomcat docment說明,默認實現了http1.1,現在版本的connector已經早不提供http1.0支持了,
難道我們要退回到http1.0的版本?那是多么痛苦的事情。再查查tomcat/conf/server.xml里關于connector
的配置,有一個參數connecttimeout,默認是20000ms, 作為服務器不可能爭對socket accept()的,應該是
socket recv()的超時,那么我們設置它為比我們<meta http-equiv="refresh" content="5;url=xxx">里
秒數小就可以了,保證在跳轉之前以前的tcp連接被tomcat服務器斷開就可以了,當然iptable應該在認證成功
之后不再對這個上網用戶發出的http請求重定向到認證服務器, 這個很容易做到,暫不提細節。
最后附上UML圖以方便理解:
