迁移spring-boot 1.5到2.0后,Webservices调用出现405错误

时间:2018-04-09 18:06:35

标签: java spring spring-boot undertow

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

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

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

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

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

此服务器实例配置位于我的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()是不同的:

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

我使用Spring安全配置类SecurityConfig,如下所示:

包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);

    }
}

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

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 ):

package t.i.config;

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

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

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配置中缺少某些东西。

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

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

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

编辑:我将我的身份验证WS方法更改为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调试器得到的:

Error 404 with Get request authentication

总结:

     
  • 我在获取请求时遇到404错误,在帖子
  • 上收到405错误  
  • Undertow需要明确设置上下文,否则我的身份验证过滤器不会被调用
这就像spring没有处理我的任何@RestController,但它们仍然是instanciated(我用控制台打印到构造函数中测试它们)。

2 个答案:

答案 0 :(得分:0)

您的方法已映射到POST请求,405表示不允许使用方法。 那是因为你发送了我认为的GET请求。

将映射更改为@GetMapping("api/authenticate")或使用Postman之类的工具发送POST请求。

我会推荐Postman方法,因为做一些像auth wuth POST请求这样的事情是个好主意。

答案 1 :(得分:0)

Spring Boot正在使用WebMvcConfigurationSupport表示它不应该自动配置Spring MVC。请尝试将extends WebMvcConfigurationSupport替换为implements WebMvcConfigurer