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

标签 java spring spring-boot undertow

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

<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 配置中,towServerInstance() 下的方法有所不同:

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

    }
}

此类用于根据用户凭据生成新 token ,或检查 header 中存在的 token 有效性(每个请求都会调用此过滤器,并且它仍然有效):

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 身份验证过滤器方法并创建 token ,但从未调用此 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

总结:

  • 我的 get 请求出现 404 错误,post 出现 405 错误
  • Undertow 需要显式设置上下文,否则不会调用我的身份验证过滤器
就像 spring 不处理我的任何 @RestController 但它们仍然被实例化(我使用控制台打印到构造函数中测试了它们)。

编辑:它现在可以与 Spring Boot 2.1.8.RELEASE 一起使用! (我不知道它可以从哪个 Spring Boot 版本开始工作,因为我从 Spring Boot 1.5.7.RELEASE 切换到 2.1.8.RELEASE)

最佳答案

您已将方法映射到 POST 请求,405 表示方法不允许。 我认为这是因为您正在发送 GET 请求。

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

我会推荐 Postman 方法,因为执行诸如 auth wuth POST 请求之类的操作是个好主意。

关于java - 将 spring-boot 1.5 迁移到 2.0 后,Webservices 调用出现 405 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49739072/

相关文章:

java - 如何在首次部署应用程序时运行查询,然后在生命周期的其余部分保留数据

java - Junit Spring 避免加载两次应用程序上下文数据源

java - 线性规划-如何将变量设置为0或1?

java - Jboss AP6 事务管理器实现

java - 理解Java中的继承

spring - @SpringBootTest 和 @Transactional 导致测试卡住

spring-boot - 集成测试 - 无法打开 ServletContext 资源/application.properties

javac 找不到符号(方法)

java - spring jpa中根据实体从多个表中获取数据

java - Spring 按类顺序对 bean 进行排序