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-х - подробности о том, как это сделать, здесь.

Другие вопросы по тегам