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