代码之家  ›  专栏  ›  技术社区  ›  systemdebt

400错误请求在Spring引导中返回,即使在请求到达筛选器之前

  •  1
  • systemdebt  · 技术社区  · 7 年前

    我有一个带有GET服务的Spring引导应用程序。

    @RequestMapping(value = "/abc/track/{type}", method = RequestMethod.GET)
    
        public void DummFunc(                            
              @RequestParam(value="subs", required = false) String sub,
    ,  HttpServletResponse response) {}
    

    价值观 subs 是一个编码值。

    如果我将下列值传递给参数subs

    {%22endpoint%22:%22https://def.abc.com/tyu/send/eD3vpGNQW28:APA91bHOo8rYrV0xccdQz3okjZJG-QGrJX8LG6ahJnEUpMNfGedqi3hJxQsJx_8BMbH6oDjaSPPEXqzNWchWrGSkhuTkSdemikkys1U22Ipd7MsRw0owWbw89V2fslIVAJ6G5lkyvYuQ%22,%22expirationTime%22:null,%22keys%22:{%22p256dh%22:%22BK0pktn50CMsTQtqwdPlKlJtdFs0LFeXX14T1zgoz6QWnvSTp5dxtChnUP5P1JX0TsjcopbdPKyN31HfABMUyic%22,%22auth%22:%22qbO_z0vGao9wD-E5g8VU-A%22}}
    

    它无法捕获请求,并且控制不在函数内部。

    如果我们将作为值传递给参数subs:

    %7B%22endpoint%22:%22https://def.abc.com/tyu/send/dX5q5eV7hFQ:APA91bHib-0QXrMzjatcvTR_uaIeeJK8lf6GmXUC9Jxv0Oxth-BzD4GmWnd4-YpDZv8qSFZ0eSg9mB2YkRvkc5ezdXW5KeaHjuQZfdyDxyBXjJgE-25Xbtlk37pdm8vfLk20k0k_VxW9%22,%22expirationTime%22:null,%22keys%22:%7B%22p256dh%22:%22BCCvcBLpRqp4u0auP688_MUJLsAiwWlQSn5kpyl8YVsEo_J-KpSdnhCmVIE_BhDXBcFYflPK52hqhYf3EaOCyuY%22,%22auth%22:%22iKuW_ESkCZnubWcQu_JK8w%22%7D%7D
    

    它很好用。

    基本上,遇到问题的请求 { } 而不是 %7B %7D .

    我的问题不是应用程序因400个错误请求而失败,而是如何在应用程序中捕获这些请求,对它们进行正确编码,然后处理它们,或者至少可以处理此错误

    此外,我还尝试添加过滤器和restcontroller建议。

    迄今为止的发现:

    1. 我意识到,可能请求甚至没有到达应用程序,因为如果我删除 DummFunc 从映射到请求的代码 /abc/track/{type} ,它仍然不返回 404 但只有400。
    2. CommonsLoggingFilter 不是用400个错误的响应代码记录这个特定的请求,但是能够记录其余的请求(另一个提示是请求没有命中应用程序-我猜)
    3. 调试时,我意识到如果我从Chrome应用程序 Postman 和浏览器,它返回400个错误的请求,但是如果我从桌面点击这个API 邮递员 应用程序,返回200。
    4. 我还尝试通过一个新类在控制器中添加异常处理程序,但没有一个捕获到请求。

    // @ResponseStatus(HttpStatus.BAD_REQUEST)
            @ExceptionHandler(Throwable.class)
            public void handle(HttpMessageNotReadableException e) {
                System.out.println("EXCEPTION HAPPENED");
                System.out.println(e);
            }

    在my application.properties中,相关的属性如下:

    spring.http.encoding.charset=UTF-8
    spring.http.encoding.enabled=true
    spring.http.encoding.force=true
    
    #security.user.name=user
    #security.basic.enabled=true
    
    
    logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG,stdout
    log4j.logger.httpclient.wire=DEBUG,stdout
    management.endpoints.web.exposure.include=*
    management.endpoint.beans.cache.time-to-live=10s
    server.tomcat.accesslog.enabled = true
    log4j.logger.org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod=DEBUG,stdout
    logging.level.org.springframework.web=DEBUG,stdout
    server.tomcat.uri-encoding=UTF-8
    

    那么,怎样才能正确处理呢?

    我正在使用 IntelliJ 它是嵌入的 Tomcat 服务器。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Akhila Madari    7 年前

    我强烈建议你使用 RequestMethod.POST 相反 RequestMethod.GET .

    "{", "}", "|", "\", "^", "~", "[", "]", and " “`都是”不安全的字符“,您使用%7b和%7d非常聪明,这应该是有效的,只要确保您使用的是正确的顺序%7b和%7d。

    在邮递员身上,它们起作用是因为邮递员将大括号解释为环境变量。如果我错了,请纠正我,但我想邮递员会返回200,但您的应用程序仍然没有收到任何数据。(对吗?)

    还有另一个可能的解决方案… 400意味着该错误假定在客户端,只需尝试将加密数据作为简单字符串发送,然后在服务器端处理该字符串。

    祝你好运!

        2
  •  0
  •   systemdebt    7 年前

    基本上,问题是 Tomcat 没有让请求通过。

    Tomcat 7.0.76、8.0.42和8.5.12中引入了这种行为,以符合RFC7231。

    可以使用中的属性requestTargetAllow恢复此强制检查 catalina.properties 允许禁止字符:

    tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}
    

    因为我在Intellij中使用嵌入式Tomcat,无法编辑 cataline.properties 直接,我补充说

    -Dtomcat.util.http.parser.HttpParser.requestTargetAllow=|{}
    

    VM Options 在里面 Run -> Edit Configuration .