http協議中的重定向
client:
向server傳送一個請求,要求獲取一個資源
server:
接收到這個請求後,發現請求的這個資源實際存放在另一個位置
於是server在返回的response header的Location欄位中寫入那個請求資源的正確的URL,並設定reponse的狀態碼為30x
client:
接收到這個response後,發現狀態碼為重定向的狀態嗎,就會去解析到新的URL,根據新的URL重新發起請求
狀態碼
重定向最常用為301,也有303,
臨時重定向用302,307
與請求轉發的對比
請求轉發
伺服器在處理request的過程中將request先後委託多個servlet或jsp接替進行處理的過程,request和reponse始終在期間傳遞
- 重定向時,客戶端發起兩次請求,而請求轉發時,客戶端只發起一次請求
- 重定向後,瀏覽器位址列url變成第二個url,而請求轉發沒有變(請求轉發對於客戶端是透明的)
- 流程
重定向:
使用者請求-----》伺服器入口-------》元件------>伺服器出口-------》使用者----(重定向)---》新的請求
請求轉發
使用者請求-----》伺服器入口-------》元件1---(轉發)----》元件2------->伺服器出口-------》使用者
服務端實現
- 重定向
response.sendRedirect()
- 請求轉發
在Servlet裡,實現dispatch是通過RequestDispatchers來實現的,這個類有兩個方法:forward,include
JSP裡實現dispatch的標籤也有兩個:和
okhttp中的實現
邏輯
- 讀取到響應狀態碼為30x時,拿到重定向的url,用這個url置換掉request中的原url
- 對request的一些header,body分情況進行處理
- 重新執行這個request,發出請求
程式碼實現
在RetryAndFollowUpInterceptor的intercept方法中構建了while (true)迴圈,迴圈內部:
###1. 根據response重建request:Request followUp = followUpRequest(response)
int responseCode = userResponse.code();複製程式碼
然後switch (responseCode)進行判斷:
2.重新執行這個request:
將前一步得到的followUp 賦值給request,重新進入迴圈,
@Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
...
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response = null;
boolean releaseConnection = true;
try {
response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);//執行網路請求
releaseConnection = false;
...
Request followUp = followUpRequest(response);//拿到重定向的request
if (followUp == null) {
if (!forWebSocket) {
streamAllocation.release();
}
return response;//如果不是重定向,就返回response
}
...
if (++followUpCount > MAX_FOLLOW_UPS) {//有最大次數限制20次
streamAllocation.release();
throw new ProtocolException("Too many follow-up requests: " + followUpCount);
}
request = followUp;//把重定向的請求賦值給request,以便再次進入迴圈執行
priorResponse = response;
}
}複製程式碼
okhttp的相關配置
重定向功能預設是開啟的,可以選擇關閉,然後去實現自己的重定向功能:
new OkHttpClient().newBuilder()
.followRedirects(false) //禁制OkHttp的重定向操作,我們自己處理重定向
.followSslRedirects(false)//https的重定向也自己處理複製程式碼