Spring Boot POST 请求返回 http 状态 405“方法不允许”而不是 HTTP 状态 404

Posted

技术标签:

【中文标题】Spring Boot POST 请求返回 http 状态 405“方法不允许”而不是 HTTP 状态 404【英文标题】:Spring Boot POST requests returning http status 405 "Method Not Allowed" instead of HTTP status 404 【发布时间】:2021-09-19 21:54:02 【问题描述】:

当向应用程序中不存在的端点发送 POST 请求时,服务器返回 405 而不是 404。具有现有端点的请求也会出现类似的问题,只要一切正常,状态码就会返回 200,但是当发生内部服务器错误(例如找不到用户)时,http 响应变为 405(而不是 500)。使用 GET 请求一切正常。

奇怪的是,如果我装上调试器,并按照错误的过程进行抛出,它正在处理一个 500 错误。但显然最终某处出了点问题,我得到了 405 返回。

我的网络安全配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

  @Autowired
  private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

  @Autowired
  private UserDetailsService jwtUserDetailsService;

  @Autowired
  private JwtRequestFilter jwtRequestFilter;

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
    // configure AuthenticationManager so that it knows from where to load
    // user for matching credentials
    // Use BCryptPasswordEncoder
    auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
  

  @Bean
  public PasswordEncoder passwordEncoder() 
    return new BCryptPasswordEncoder();
  

  @Bean
  @Override
  public AuthenticationManager authenticationManagerBean() throws Exception 
    return super.authenticationManagerBean();
  

  @Value("$allowedOrigin")
  private String origin = "http://localhost:4200";

  @Override
  protected void configure(HttpSecurity httpSecurity) throws Exception 
    //You can enforce the use of HTTPS when your app is running on Heroku by adding
    // the following configuration to your Spring Boot app.
    httpSecurity.requiresChannel()
      .requestMatchers(r - > r.getHeader("X-Forwarded-Proto") != null)
      .requiresSecure();


    httpSecurity
      .cors()
      .and().csrf()
      .disable()
      // dont authenticate this particular request
      .authorizeRequests()
      .antMatchers("/api/authenticate")
      .permitAll()
      // all other requests for /api need to be authenticated
      .antMatchers("/api/**", "/admin/**")
      .authenticated()
      .and()
      .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    // Add a filter to validate the tokens with every request
    httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

  

  @Bean
  CorsConfigurationSource corsConfigurationSource() 
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("*"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
  

更新:

我没有任何 ControllerAdivce,也没有编写全局异常处理程序。

405 响应中的“Allow”标头读取“GET, HEAD”,即使 POST 请求实际进入 POST 端点也是如此。

【问题讨论】:

是否有任何ControllerAdivce或全局异常处理程序编写? 不,没有 ControllerAdvice 也没有编写全局异常,这是一个相当新的项目。这就是它如此令人沮丧的原因,我看不出它可能哪里出错了。奇怪的是,当我做一个 POST 时,它进入了端点,但标题说“允许”:“GET,HEAD” 【参考方案1】:

根据您的 HttpSecurity 配置,您只允许 Post 请求,对于 GET、PUT 等其他 HTTP 方法,您将获得 405(不允许的方法)......

 antMatchers(HttpMethod.POST).permitAll();

【讨论】:

我添加了该部分作为解决方法,同时我删除了它......它不需要在那里。 antMatchers(HttpMethod.POST).permitAll();这样做是允许所有 POST 请求,并且不需要角色或身份验证。它不会阻止其他 HTTP 方法请求,例如 GET、PUT、...【参考方案2】:

原来是一个带有未实现的“/error”路径方法的 ErrorController 导致了问题。每当抛出异常或错误时,它都会被解析为“/error”并由 ErrorController 拾取,由于某种原因将其解析为 405。实现该方法后,HTTP 状态将正确返回。

@RestController
public class RoutingController implements ErrorController 

  private static final String PATH = "/error";

  @RequestMapping(value = PATH)
  public String handleError(HttpServletRequest request) 
    Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
    Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
    return String.format("<html><body><h2>Error Page</h2><div>Status code: <b>%s</b></div>" +
      "<div>Exception Message: <b>%s</b></div><body></html>",
      statusCode, exception == null ? "N/A" : exception.getMessage());
  

  public String getErrorPath() 
    return PATH;
  

【讨论】:

以上是关于Spring Boot POST 请求返回 http 状态 405“方法不允许”而不是 HTTP 状态 404的主要内容,如果未能解决你的问题,请参考以下文章

spring boot应用集成cas单点登录,post请求拿不到参数

执行 POST 请求时的 Spring Boot 端点 403 OPTIONS

Spring boot - 一些 POST 请求严重延迟

缺少请求正文的 Spring Boot POST 请求?

无法将http post请求发送到spring boot

Spring Boot - 模拟对外部 API 的 POST REST 请求