将 spring-boot 1.5 迁移到 2.0 后 Web 服务调用出现 405 错误 [英] 405 error on Webservices calls after migrating spring-boot 1.5 to 2.0

查看:58
本文介绍了将 spring-boot 1.5 迁移到 2.0 后 Web 服务调用出现 405 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我缺乏 Spring 配置知识,我面临一个无法解决的问题:每个 GET 返回错误 404 和每个 POST 返回错误 405.我的 spring 安全过滤器运行良好,但 @PostMapping 或 @GetMapping 注释方法都没有被调用.我已经将旧属性 server.context-path 重命名为新名称 server.servlet.context-path 但它仍然无法正常工作.我使用 undertow 网络服务器:

I am facing an unsolvable problem with my poor spring configuration knowledge: every GET return error 404 and every POST return error 405. My spring security filters work well but neither @PostMapping or @GetMapping annotated methods are getting called. I have taken care of rename old property server.context-path to new name server.servlet.context-path but it still not working. I use undertow webserver:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
    <version>${springBoot.version}</version>
</dependency>

我的 app.properties 文件真正命名为 application.mssql.properties:

My app.properties file is really named application.mssql.properties:

## Hibernate properties
... some properties ...

##Spring boot properties
server.servlet.context-path =/my-context

这个服务器实例配置在我的 ApplicationConfiguration 中:

And this server instance configuration is in my ApplicationConfiguration:

@SpringBootApplication(scanBasePackages = { 
    "t.i.DAO", 
    "t.i.SERVICES",
    "t.i.config", 
    "t.i.config.security" })
@PropertySource({ "classpath:application.mssql.properties" })
@EnableCaching
@EnableTransactionManagement
public class ApplicationConfiguration {

    // Properties of application.mssql.properties file
    @Autowired
    private Environment env;

    ... some code there...

   @Bean
   public ConfigurableServletWebServerFactory undertowServerInstance() { 
        UndertowServletWebServerFactory customizer = new UndertowServletWebServerFactory();
        customizer.addBuilderCustomizers((builder) -> {
            builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true);
        });

        // EDIT: add: set the context by reading app.properties
        customizer.setContextPath(env.getProperty("server.servlet.context-path"));
        return customizer;
   }
}

请注意,在我旧的 spring 1.5 配置中,undertowServerInstance() 方法是不同的:

Notice that with my old spring 1.5 configuration, the method undertowServerInstance() was different:

@Bean
public EmbeddedServletContainerCustomizer undertowServerInstance() {
    return (container) -> {
        if(container instanceof UndertowEmbeddedServletContainerFactory) {
            ((UndertowEmbeddedServletContainerFactory) container)
                .addBuilderCustomizers(builder -> builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
        }
    };
}

我像这样使用 Spring 安全配置类 SecurityConfig:

I use a Spring security configuration class SecurityConfig like this:

打包 t.i.config;

package t.i.config;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // allows AOP @PreAuthorize and some other annotations to be applied to methods.
@EnableWebSecurity
@EnableScheduling // allows to run Spring schedulers and periodically run some tasks. We use scheduler for evicting EhCache tokens.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        ... some code for security configuration ...

        // adding authentication filter
        http.addFilterBefore(new AuthenticationFilter(this.authenticationManager), BasicAuthenticationFilter.class);

    }
}

此类用于从用户凭据生成新令牌或检查令牌有效性是否存在于标头上(此过滤器为每个请求调用并且它仍然有效):

This class is used to generate a new token from user credentials or check token validity if it is present on header (this filter is called for every requests and it still work):

package t.i.config.security;

public class AuthenticationFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        try {
            // check or create token. Exception if credentials or token invalid
        }
        catch(AuthenticationException authenticationException){
            ((HttpServletResponse) http).sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
            return;
        }

        chain.doFilter(request, response);
    }
}

这是我的 WebMvcConfig,其中包含 @RestController 类包位置(添加了实现 WebMvcConfigurer):

This is my WebMvcConfig which contain @RestController classes package location (edit: added implements WebMvcConfigurer) :

package t.i.config;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"t.i.controllers"})
public class WebMvcConfig implements WebMvcConfigurer {
 ... code there ... 
}

并且,例如,当我调用 /api/authenticate URL 时,会调用我的 spring 身份验证过滤器方法并创建令牌,但从未调用此 WS(而是返回 405):

And, for example, when I call /api/authenticate URL, my spring authentication filter method is called and token created but this WS is never called (returning 405 instead):

package t.i.controllers;

@RestController
public class AuthenticationController {


    @PostMapping("api/authenticate")
    public UserDTO authenticate(AuthenticationWithToken principal) {

        ... some code there that is never called with spring boot 2.0 ...

        return userDTO;
    }
}

我仍然不明白这个问题,我认为 Undertow 配置中缺少一些东西.

I still don't understand this problem and I think something is missing in Undertow configuration.

ApplicationConfiguration.undertowServerInstance() 方法中,如果我删除该行:

In the ApplicationConfiguration.undertowServerInstance() method, if I remove the line:

// EDIT: add: set the context by reading app.properties
customizer.setContextPath(env.getProperty("server.servlet.context-path"));

然后 AuthenticationFilter 不再被触发.使用 spring boot 1.5,我不需要明确指定 Undertow 上下文.

Then the AuthenticationFilter is not triggered any more. With spring boot 1.5 I never need to explicitly specify Undertow context.

我将我的身份验证 WS 方法更改为 GET:

I changed my authentication WS method to GET:

 package t.i.CONTROLLERS;

@RestController
public class AuthenticationController {

    @RequestMapping(value = "/api/authenticate", method = RequestMethod.GET)
    public UserDTO authenticate(AuthenticationWithToken principal) {

        ... some code there that is still never called with spring boot 2.0 ...

        return userDTO;
    }
}

身份验证过滤器运行良好,但方法 AuthenticationController.authenticate 仍未被调用.这是我用 chrome 调试器得到的:

The authentication filter works well but method AuthenticationController.authenticate is still not called. This is that I got with chrome debugger:

总结:

  • get 请求出现 404 错误,post 出现 405 错误
  • Undertow 需要明确设置上下文,否则不会调用我的身份验证过滤器
  • 它现在适用于 spring boot 2.1.8.RELEASE!(我不知道从哪个 spring boot 版本开始它可以工作,因为我从 spring boot 1.5.7.RELEASE 切换到 2.1.8.RELEASE)

    It works now with spring boot 2.1.8.RELEASE! (I have no idea since which spring boot version it could be working because I switched from spring boot 1.5.7.RELEASE to 2.1.8.RELEASE)

    推荐答案

    Spring Boot 将您对 WebMvcConfigurationSupport 的使用视为它不应自动配置 Spring MVC 的指示.尝试将 extends WebMvcConfigurationSupport 替换为 implements WebMvcConfigurer.

    Spring Boot is taking your use of WebMvcConfigurationSupport as an indication that it shouldn't auto-configure Spring MVC. Try replacing extends WebMvcConfigurationSupport with implements WebMvcConfigurer instead.

    这篇关于将 spring-boot 1.5 迁移到 2.0 后 Web 服务调用出现 405 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆