Http адаптер входящего канала реагирует на слишком много путей - PullRequest
0 голосов
/ 03 мая 2018

У меня есть работающее приложение интеграции пружин, к которому я добавил конечную точку HTTP в /requests для получения данных POST от клиента REST (на самом деле веб-браузер); Я добавляю набор других конечных точек REST также с помощью Spring MVC , одна из которых обрабатывает запросы GET для /api/requests & mdash; эти конечные точки REST предназначены для обеспечения взаимодействия клиентов только для чтения.

Конечная точка интеграции Spring работает, когда она вызывается, как и ожидалось (то есть с прямым вызовом /requests), но я испытываю, что она «перехватывает» даже запросы, которые она не должна: т.е. /api/requests.

Я не использую Spring Boot. Я настраиваю свою конфигурацию из примера на Home Integration , перенося ее из приложения в веб-приложение позже.

Это 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]? Это работает, но мне неясно, какое имя сервлета должно соответствовать какому имени компонента (как сказано в Входящие компоненты Http ), возможно, это идентификатор контекстного компонента & harr; web.xml имя сервлета ?
  2. необходимо ли отображение в [b]? Я не мог заставить входящий адаптер работать без него, но, возможно, его следует настроить по-другому, так как в вышеупомянутых документах не показано сопоставление для HttpRequestHandlerServlet servlet

И главный вопрос:

  1. почему этот адаптер перехватывает другие остальные вызовы? Я получаю:

    HTTP Status 405 - Request method 'GET' not supported
    

    при вызове /api/requests, который четко показывает входящий адаптер.

Я сделал некоторую отладку, и поведение, похоже, контролируется UrlPathHelper.alwaysUseFullPath, который меняет "/ api / запросы" на "/ запросы" Если бы это свойство можно было установить на true, все работало бы, как я могу это сделать?


ОБНОВЛЕНИЕ # 1

Я обновил свою конфигурацию после этого ответа , но у меня все еще есть проблемы.

Я получаю 404 от запроса клиента, и это предупреждение появляется в журнале приложения:

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

Это новый context.xml с новыми id s:

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

<?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, я все равно получаю то же предупреждение:

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

Это новый context.xml с новым id s:

<?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

Хотя это и не показано выше, это то же приложение, что и в , этот другой вопрос , вот контроллер, который должен ответить на GET s в течение /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));
    }

    // ...

Это изменение заставило GET s работать снова, но затем POST s больше не работает.

Это происходит из-за кода в DispatcherServlet#getHandler(), где экземпляр типа RequestMappingInfoHandlerMapping от члена handlerMappings распознает запрос к /api/requests, но отклоняет метод POST, выбрасывая исключение, из-за которого выполнение выходит за пределы запрос обработчика поиска.

1 Ответ

0 голосов
/ 03 мая 2018

В этой документации у нас есть это предложение:

Если вы работаете в приложении Spring MVC, то вышеупомянутое явное определение сервлета не обязательно.

Так как у вас есть DispatcherServlet, вам не нужно это конкретное HttpRequestHandlerServlet для вашего httpInboundAdapter.

Поэтому вы также удаляете это <url-pattern>/requests</url-pattern>, и весь REST API будет находиться под /api/* и там не будет выставлено /requests на основании упомянутого UrlPathHelper.alwaysUseFullPath.

...