2014-04-15 28 views
2

我有一個奇怪的問題,如果我的servlet發送200 ok http狀態,它按預期方式工作,並且客戶端按預期獲得200狀態。但是,如果我的servlet返回404狀態,則tomcat似乎將其更改爲403狀態。如果我使用http get方法,則不會發生這種情況。我還沒有測試putposttomcat將404狀態更改爲403用於http刪除

我想說清楚的是,我的servlets doDelete方法得到了很好的執行。只是返回到瀏覽器的狀態代碼發生了變化。

我會提供一個最小的測試用例來說明問題。

import javax.servlet.annotation.WebServlet; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

@WebServlet("/api/test403/*") 
public class Test403 extends HttpServlet { 
    public void doDelete(HttpServletRequest request, HttpServletResponse response) { 
     try { 
      String p = request.getParameter("send404"); 
      if (p != null && "1".equals(p)) { 
       response.sendError(HttpServletResponse.SC_NOT_FOUND, "not found."); 
      } else { 
       response.sendError(HttpServletResponse.SC_OK, "ok."); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
    private static final long serialVersionUID = 1L; 
} 

然後我通過以下網址

myproject/api/test403?send404=1 
myproject/api/test403?send404=0 

什麼可能導致此行爲測試?我並不太熟悉整個servlet /容器體系結構。我只在1臺使用tomcat 7.0.41的服務器上遇到這個問題。我嘗試了另一臺服務器,但沒有出現這種行爲。

編輯 - 根據要求,這裏是一些網絡面板的輸出。我用阿賈克斯來發起這個特殊的請求:

Request Headers 

DELETE /xxxxx HTTP/1.1 
Host: xxxxx 
Connection: keep-alive 
Origin: xxx 
X-Requested-With: XMLHttpRequest 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36 
Content-Type: application/x-www-form-urlencoded 
Accept: */* 
Referer: xxx 
Accept-Encoding: gzip,deflate,sdch 
Accept-Language: en-US,en;q=0.8 
Cookie: xxx 

Response Headers 

HTTP/1.1 403 Forbidden 
Server: Apache-Coyote/1.1 
Content-Type: application/json;charset=UTF-8 
Transfer-Encoding: chunked 
Content-Encoding: gzip 
Vary: Accept-Encoding 
Date: Wed, 16 Apr 2014 02:30:32 GMT 

我沒有刪除任何頭,雖然我匿名了一些值。

+0

我無法在7.0.41上重現此操作。你使用的是什麼Http客戶端? –

+0

@SotiriosDelimanolis我使用了瀏覽器插件 - 用於Chrome的Advanced Rest Client,以及用於Firefox的HttpRequester。 – goat

+0

您可以發佈網絡控制檯的圖片或顯示請求/響應標頭/正文的內容嗎? –

回答

4

的組合...

  • 一個http請求DELETE
  • 呼籲HttpServletResponse.sendError(status, message)從你的servlet發送404 doDelete()方法
  • 配置自定義404錯誤頁面處理程序(例如,通過<error-page>web.xml
  • 保留readonly = true的默認值爲您的上下文

將導致客戶端收到403狀態,而不是您發送的404狀態。

對servlet的請求可以爲http刪除請求提供服務,而不需要readonly爲false,但對文件的請求不能。會發生什麼情況是,當你打電話給sendError()時,tomcat將嘗試找到一個自定義的錯誤頁面,它與你指定的任何http狀態相匹配。在這種情況下,它找到一個(/my404.html),所以爲了處理它,它基本上重新啓動了整個請求路由/分派過程,包括運行請求上的所有過濾器。但是,這一次,由於它是一個靜態文件請求,因此會出現一個內置過濾器,該過濾器會查找http方法,然後檢查是否爲readonly = false。如果不是,請求被拒絕,並且它將響應狀態更改爲禁止403,因爲您不允許刪除名爲/my404.html的靜態文件。

明智的解決方法是使用HttpServletResponse.setStatus(status)而不是HttpServletResponse.sendError(status, message),這樣tomcat就不會找到錯誤頁面。

+0

我在Glassfish上遇到了404.html錯誤頁面和JAX-RS Response類的相同問題。不幸的是,試圖使用'return Response.status(404).build();'不起作用。任何想法爲什麼? –

+0

哦,顯然你還必須設置一些內容以及狀態,否則錯誤頁面仍然會返回。所以你必須做'返回Response.status(404).entity(「Error code 404」)。build();'而不是。在你的回答中可能會提到這一點。 –