简体   繁体   English

tomcat将404状态改成403进行http删除

[英]tomcat changes 404 status into 403 for http delete

I'm having a weird issue where if my servlet sends a 200 ok http status, it works as intended, and the client gets a 200 status as expected.我有一个奇怪的问题,如果我的 servlet 发送 200 ok http 状态,它会按预期工作,并且客户端按预期获得 200 状态。 But, if my servlet returns a 404 status, tomcat seems to change it into a 403 status.但是,如果我的 servlet 返回 404 状态,tomcat 似乎会将其更改为 403 状态。 This doesn't happen if I use the http get method.如果我使用 http get方法,则不会发生这种情况。 I haven't tested put or post .我还没有测试putpost

I want to make it very clear that my servlets doDelete method gets executed just fine.我想非常清楚地说明我的 servlet 的doDelete方法执行得很好。 It's just that the status code returned to the browser gets changed.只是返回给浏览器的状态码发生了变化。

I'll provide a minimal testcase demonstrating the issue.我将提供一个最小的测试用例来演示这个问题。

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;
}

then i test via the following urls然后我通过以下网址进行测试

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

What could cause this behavior?什么可能导致这种行为? I'm not overly familiar the whole servlet/container architecture.我不太熟悉整个 servlet/容器架构。 I'm only experiencing this issue on 1 server which uses tomcat 7.0.41.我只在 1 台使用 tomcat 7.0.41 的服务器上遇到这个问题。 I tried another server, which didn't exhibit this behavior.我尝试了另一台服务器,它没有表现出这种行为。

edit - Per request, here's some output from the network panel in chrome.编辑 - 根据请求,这里是 chrome 网络面板的一些输出。 I used ajax to initiate this particular request:我使用 ajax 来发起这个特定的请求:

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

I didn't remove any headers, although I anonymized some values.我没有删除任何标题,尽管我匿名了一些值。

A combination of...组合...

  • an http DELETE request一个 http DELETE请求
  • calling HttpServletResponse.sendError(status, message) to send the 404 from your servlets doDelete() method调用HttpServletResponse.sendError(status, message)从您的 servlet doDelete()方法发送 404
  • configuring a custom 404 error handler page(eg, via the <error-page> directive in web.xml )配置自定义 404 错误处理程序页面(例如,通过web.xml<error-page>指令)
  • Keeping the default value of readonly = true for your context为您的上下文保留readonly = true的默认值

will cause the client to receive a 403 status instead of the 404 you though you sent.将导致客户端收到 403 状态而不是您发送的 404 状态。

A request to a servlet can service an http delete request without needing readonly to be false, but a request to a file cannot.对 servlet 的请求可以在不需要readonly为 false 的情况下为 http 删除请求提供服务,但对文件的请求不能。 What happens is that when you call sendError() , tomcat will try to find a custom error page that matches up with whatever http status you specified.发生的情况是,当您调用sendError() ,tomcat 将尝试查找与您指定的任何 http 状态匹配的自定义错误页面。 In this case, it found one ( /my404.html ), and so in order to process it, it basically restarts the entire request routing/dispatching process, including running all the filters on the request.在这种情况下,它找到了一个( /my404.html ),因此为了处理它,它基本上重新启动了整个请求路由/调度过程,包括对请求运行所有过滤器。 But, this time, since it's a static file request, it comes across a built in filter that looks for http the DELETE method, and then checks if readonly = false .但是,这一次,由于它是一个静态文件请求,它遇到了一个内置过滤器,该过滤器会查找 http 的DELETE方法,然后检查readonly = false If it's not, the request is rejected, and it changes the response status to 403 forbidden because you're not allowed to delete the static file named /my404.html .如果不是,则请求被拒绝,并将响应状态更改为 403 forbidden 因为您不允许删除名为/my404.html的静态文件。

A sensible workaround is to use HttpServletResponse.setStatus(status) instead of HttpServletResponse.sendError(status, message) , so that tomcat doesn't try to find an error page.一个明智的解决方法是使用HttpServletResponse.setStatus(status)而不是HttpServletResponse.sendError(status, message) ,这样 tomcat 就不会尝试查找错误页面。 As mentioned by @BogdanZurac , you may also need to send a brief response body (ie, "oops Error 404") in addition to setting the status to prevent it from seeking the custom error page.正如@BogdanZurac 所提到的,除了设置状态以防止它寻找自定义错误页面之外,您可能还需要发送一个简短的响应正文(即“oops Error 404”)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM