【问题标题】:Http inbound channel adapter responds to too many pathsHttp 入站通道适配器响应路径过多
【发布时间】:2018-05-03 13:16:17
【问题描述】:

我有一个工作的 spring 集成应用程序,我在/requests 下添加了一个 HTTP 端点,以从 REST 客户端(实际上是一个 Web 浏览器)接收 POST 数据;我也通过 Spring MVC 添加了一组其他 REST 端点,其中一个处理对/api/requests 的 GET 请求——这些 REST 端点旨在为客户。

spring 集成端点在按预期调用时工作(即直接调用/requests),但我体验到它正在“捕获”,即使它不应该请求:即/api/requests

我没有使用 Spring Boot。我根据Integration home 上的示例调整了我的配置,稍后将其从应用程序移动到 Web 应用程序。

这是context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:...>

    <ctx:component-scan base-package="services,api"  />

    <int-http:inbound-channel-adapter id="httpInboundAdapter"
        channel="httpRequestsChannel"
        path="/requests"
        supported-methods="POST">
        <int-http:cross-origin allow-credentials="false" allowed-headers="*" origin="*" />
    </int-http:inbound-channel-adapter>

    <!-- other channels and endpoints -->

    <!-- misc beans -->

    <!-- other beans: jdbc-datasource, etc -->

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

</beans>

以及web.xml的(相关部分):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          version="3.0">

    <!-- [a] -->
    <servlet>
        <servlet-name>httpInboundAdapter</servlet-name>
        <servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
    </servlet>

    <!-- [b] -->
    <servlet-mapping>
        <servlet-name>httpInboundAdapter</servlet-name>
        <url-pattern>/requests</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/META-INF/spring.integration/context.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

</web-app>

初步问题:

  1. [a] 中的 servlet 是否配置正确?这可行,但我不清楚哪个 servlet 名称应该匹配哪个 bean 名称(如 Http Inbound Components 中所说),也许它是 context bean idweb.xml servlet 名称?
  2. [b] 中的映射是否必要?没有它我无法让入站适配器工作,但也许它应该以另一种方式配置,因为上述文档显示没有 HttpRequestHandlerServlet servlet 的映射

还有主要问题:

  1. 为什么那个适配器会拦截其他的休息调用?我得到:

    HTTP Status 405 - Request method 'GET' not supported
    

    当调用 /api/requests 时,它清楚地显示适配器正在介入。

我做了一些调试,行为似乎由 UrlPathHelper.alwaysUseFullPath 控制,将“/api/requests”更改为“/requests”。 如果这个属性可以设置为true 整个就可以了,我该怎么做呢?


更新 #1

我在this answer之后更新了配置,但还是有问题。

我从客户端请求中收到 404,并且此警告出现在应用程序日志中:

WARNING: No mapping found for HTTP request with URI [/api/requests] in DispatcherServlet with name 'app'

这是新的context.xml 和新的ids:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:...>

    <ctx:component-scan base-package="services,api"  />
    <ctx:annotation-config />
    <mvc:annotation-driven />

    <int-http:inbound-channel-adapter id="/api/requests"
        channel="httpRequestsChannel"
        path="/api/requests"
        supported-methods="POST">
        <int-http:cross-origin allow-credentials="false" allowed-headers="*" origin="*" />
    </int-http:inbound-channel-adapter>

    <int-http:inbound-channel-adapter id="/api/requests"
        channel="nullChannel"
        path="/api/requests"
        supported-methods="OPTIONS">
        <int-http:cross-origin allow-credentials="false" allowed-headers="*" origin="*" />
    </int-http:inbound-channel-adapter>

    <!-- other channels and endpoints -->

    <!-- misc beans -->

    <!-- other beans: jdbc-datasource, etc -->

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

</beans>

并且我从web.xml中删除了servlet声明和映射:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          version="3.0">

    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <!-- ... -->

更新 #2

另一个审查,删除重复的 id bean,我仍然得到相同的警告:

WARNING: No mapping found for HTTP request with URI [/api/requests] in DispatcherServlet with name 'app'

这是新的context.xml 和新的ids:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:...>

        <ctx:component-scan base-package="services,api"  />
        <ctx:annotation-config />
        <mvc:annotation-driven />

        <int-http:inbound-channel-adapter id="/api/requests"
            channel="httpRequestsChannel"
            path="/api/requests"
            supported-methods="POST,OPTIONS">
            <int-http:cross-origin allow-credentials="false" allowed-headers="*" origin="*" />
        </int-http:inbound-channel-adapter>

        <int:channel id="httpRequestsChannel" />
    <!-- other channels, endpoints and beans -->

</beans>

更新 #3

正如所指出的,我已经编辑了 path 属性:POST 请求现在可以工作,但是 GET 请求现在被破坏,产生:

WARNING: Request method 'GET' not supported

虽然上面没有显示,但它与this other question 中的应用程序相同,这是应该响应GETs 而不是/api/requests 的控制器:

package api;

// imports

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping(path="/api/requests", produces="application/json")
public class RequestController {
    // ...

已编辑context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:...>

        <ctx:component-scan base-package="services,api"  />
        <ctx:annotation-config />
        <mvc:annotation-driven />

        <int-http:inbound-channel-adapter id="/api/requests"
            channel="httpRequestsChannel"
            path="/requests"
            supported-methods="POST,OPTIONS">
            <int-http:cross-origin allow-credentials="false" allowed-headers="*" origin="*" />
        </int-http:inbound-channel-adapter>

        <int:channel id="httpRequestsChannel" />
    <!-- other channels, endpoints and beans -->

</beans>

更新 #4

在此更新中,我修复了 REST 控制器主路径映射从 path="/api/requests"path="/requests"

package it.cgt.api;

// imports

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping(path="/requests", produces="application/json")
public class RequestController {

    @Autowired
    private RequestService requestService;

    @Autowired
    private ProductService productService;

    @GetMapping(path= "")
    public ApiResponse<List<Request>> getRequests(RequestFilters filters) {
        return new ApiResponse<List<Request>>(requestService.getRequests(filters));
    }

    // ...

此更改使GETs 再次工作,但随后POSTs 不再工作。

这似乎是由于 DispatcherServlet#getHandler() 中的代码,其中来自 handlerMappings 成员的 RequestMappingInfoHandlerMapping 类型的实例识别到对 /api/requests 的请求,但拒绝 POST 方法抛出异常,使执行落在请求处理程序查找。

【问题讨论】:

    标签: java spring spring-integration spring-rest


    【解决方案1】:

    在该文档中,我们有这句话:

    如果您在 Spring MVC 应用程序中运行,则不需要前面提到的显式 servlet 定义。

    由于您有DispatcherServlet,因此您的httpInboundAdapter 不需要特定的HttpRequestHandlerServlet

    因此,您还删除了 &lt;url-pattern&gt;/requests&lt;/url-pattern&gt;,所有 REST API 都将在 /api/* 下,并且不会根据提到的 UrlPathHelper.alwaysUseFullPath 暴露 /requests

    【讨论】:

    • 你能分享一个例子吗?我试图修改我的配置(参见 Update #1),但我认为我没有在 Http Inbound Components 中获得 In that case, the bean name for your gateway can be matched against the URL path just like a Spring MVC Controller bean. 文档部分。
    • 您不能对多个 bean 使用相同的 id - 最后只有 las 一个将在应用程序上下文中可用。
    • 我做到了(请参阅 Update #2)但我仍然得到 404;请记住,我是 Spring、MVC 和集成的新手。
    • 因为在web.xml 你有&lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;,尝试像`path="/requests"` 那样映射你的通道适配器。在此处查看一些示例:github.com/spring-projects/spring-integration-samples/tree/…
    • 完成。 Spring在这里做后缀匹配吗?无论如何,这修复了POSTs,但破坏了GETs(我知道他们没有出现在这个问题中,请参阅更新#3
    猜你喜欢
    • 2016-01-18
    • 2016-11-17
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多