Spring mvc: ресурс не найден, как только я добавлю третью переменную пути
Я использую Spring MVC для моего сервера REST. Spring.version в моем pom.xml - это 3.2.1.RELEASE.
Я создал несколько RESTful API и широко использовал PathVariables. Работает нормально.
Но, похоже, сломаться в следующем сценарии. Если у меня есть что-то вроде следующего, мой запрос REST не находит ресурс.
@Controller
@RequestMapping(value = { "/resourceA/{resourceAId}/resourceB/{resourceBId}/resourceC/{resourceCId}" })
public class TenderController {
@RequestMapping(value = "", method = RequestMethod.POST)
@ResponseBody
public Tender capture(
@PathVariable long resourceAId,
@PathVariable long resourceBId,
@PathVariable long resourceCId,
@RequestBody Map<String, Object> requestBody) {
...
}
}
Отредактировано:
Вот мой пример неудачного запроса REST:
POST /resourceA/1/resourceB/2/resourceC/3 HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Cache-Control: no-cache
{ "bodyParam1": 400, "bodyParam2": 0 }
Однако, если я удаляю {resourceCId} из кода Java и соответствующим образом корректирую свой запрос REST, он успешно находит ресурс:
Пересмотренный Java-код:
@RequestMapping(value = { "/resourceA/{resourceAId}/resourceB/{resourceBId}/resourceC" })
Новый (успешный) запрос REST:
POST /resourceA/1/resourceB/2/resourceC HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Cache-Control: no-cache
{ "bodyParam1": 400, "bodyParam2": 0 }
По сути, как только у меня есть 3 переменные пути, вещи, кажется, распадаются. Есть идеи о том, что здесь может происходить? Я наткнулся на ошибку Spring MVC? Я предполагаю, нет, потому что 3 переменные пути должны быть довольно распространенным сценарием (едва ли подходит для углового случая).
Обновление: это, кажется, проблема с моим клиентом HTTP (почтальоном chrome), а не с моим кодом сервера. Мне удалось получить ожидаемые результаты, когда я отправляю тот же запрос через curl.
Обновление: на самом деле ошибка вернулась и происходит независимо от клиента (почтальон, завиток и т. Д.). Так что это определенно проблема на стороне сервера. Вот логи
01:35:39.409 [http-bio-8080-exec-5] DEBUG o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 'mvc-dispatcher' processing POST request for [/resourceA/1/resourceB/1/resourceC/1]
01:35:39.411 [http-bio-8080-exec-5] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method for path /resourceA/1/resourceB/1/resourceC/1
01:35:39.414 [http-bio-8080-exec-5] DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method [public void com.sample.controller.DefaultController.unmappedRequest()]
01:35:39.414 [http-bio-8080-exec-5] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'defaultController'
01:35:39.422 [http-bio-8080-exec-5] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception from handler [public void com.sample.controller.DefaultController.unmappedRequest()]: com.sample.exception.APIException: Url pattern is invalid.
01:35:39.423 [http-bio-8080-exec-5] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'globalControllerExceptionHandler'
01:35:39.423 [http-bio-8080-exec-5] DEBUG o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Invoking @ExceptionHandler method: public com.sample.model.ErrorInfo com.sample.controller.GlobalControllerExceptionHandler.handleAPIException(com.sample.exception.APIException)
01:35:39.460 [http-bio-8080-exec-5] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [com.sample.model.ErrorInfo@df27cd5] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter@2ae18b1a]
01:35:39.460 [http-bio-8080-exec-5] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
01:35:39.460 [http-bio-8080-exec-5] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
Нашли, что вызывает проблему:
Так что, поигравшись с множеством разных вещей, я нашел причину этой проблемы. У меня есть DefaultController.java, который был предназначен для перехвата всех URL, которые не совпадают ни с одним из других контроллеров, и сообщал о хорошем ресурсе, не найденном в ответе об ошибке моей службы REST. DefaultController имеет следующий код:
package com.sample.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.sample.exception.APIException;
import com.sample.exception.APIException.Code;
@Controller
public class DefaultController {
@RequestMapping("/**")
public void unmappedRequest() {
throw new APIException(Code.INVALID_URL_PATTERN,
"There is no resource for this path");
}
}
Это хорошо сработало для меня. Но в этом случае каким-то образом этот DefaultController "/**" выбирал мой URL перед контроллером, который фактически был настроен на получение "/resourceA/{resourceAId}/resourceB/{resourceBId}/resourceC/{resourceCId}". Удаление DefaultController устранило проблему для меня. Теперь мой вопрос заключается в том, как сохранить функциональность DefaultController, не вызывая ее до моего TenderController.
1 ответ
Я считаю, что это, скорее всего, ошибка Spring, которая, возможно, будет исправлена в какой-то момент. Столкнулся с точно такой же проблемой. В нашем случае мы смогли обойти это, заменив контроллер Spring по умолчанию, который обрабатывал несопоставленные запросы, простым ванильным сервлетом для обработки 404-х - подробности о том, как это сделать, здесь.