Возвратите тип содержимого для Ответов об ошибках, основанный на условии производит - PullRequest
0 голосов
/ 26 февраля 2020

У меня есть пользовательская обработка ошибок в моем веб-сервисе REST. У меня есть методы, возвращающие XML / JSON в качестве ответа. На SpringBoot версии 2.0.9 все работало нормально. Но после перехода на последнюю ( 2.2.4 ) мои тесты по обработке ошибок не пройдены:

Content type expected:<application/xml> but was:<application/json>
Expected :application/xml
Actual   :application/json

После исследования я обнаружил, что это связано с обновлением Spring до версии 5.1, Документы:

Согласование содержимого для ответов об ошибках Условие производителей @RequestMapping больше не влияет на тип содержимого ответов об ошибках.

Как воспроизвести поведение из более ранних версий весны в последний? Я просто хочу вернуть тип содержимого для ошибок, как указано в производит условие.

Методы отдыха:

@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<Object> xmlMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {

    Object result = service.call(payload, scriptName);
    return ResponseEntity.ok(new JsonBuilder(result).getContent());
}

@PostMapping(path = "/{scriptName}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<Object> jsonMethod(@RequestParam("payload") String payload, @PathVariable("scriptName") String scriptName) {
    Object result = service.call(payload, scriptName);
    return ResponseEntity.ok(new JsonBuilder(result).getContent());
}

CustomRestExceptionHandler:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<Object> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {

        HTTPErrorDTO httpError = new HTTPErrorDTO(HttpStatus.NOT_FOUND, ex.getLocalizedMessage());
        return new ResponseEntity<>(httpError, new HttpHeaders(), httpError.getStatus());
    }

    ....
    // handlers for other exceptions
}

Ошибка DTO:

@XmlRootElement(name = "Exception")
@XmlAccessorType(XmlAccessType.FIELD)
public class HTTPErrorDTO {

    private HttpStatus status;
    private String message;
    private List<String> errors;
}

Связанные топи c: Spring mvc - Настройка обработки ошибок для XML и JSON Ответ

--- EDIT

Я попытался добавить пользовательскую конфигурацию согласования контента. Но один из клиентов моего REST API отправляет мне content-type = "application / x- www-form-urlencoded" и ожидает application / xml и не отправляет заголовки принятия.

Таким образом, я могу только решить, какой формат должен иметь тип контента на уровне метода / контроллера.

Могу ли я как-то сообщить обработчику исключений из контроллера, какой тип контента должен быть установлен?

Ответы [ 2 ]

1 голос
/ 26 февраля 2020

Вы можете передать объект HandlerMethod методу обработчика исключений (например, handleResourceNotFoundException в вашем вопросе).

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<Object> handleResourceNotFoundException(
    ResourceNotFoundException ex, 
    WebRequest request, 
    HandlerMethod handlerMethod) {
    ........        
}

Объект HandlerMethod представляет метод контроллера, вызвавший исключение. Таким образом, вы можете получить значения produces из аннотации @RequestMapping на объекте.

RequestMapping requestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
String[] produces = requestMapping.produces();
....

В исходном коде вопроса produces - это массив, содержащий элемент (то есть MediaType.APPLICATION_XML_VALUE или MediaType.APPLICATION_JSON_VALUE).

См. также
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc -ann-exceptionhandler-args

1 голос
/ 26 февраля 2020

В вашем CustomRestExceptionHandler вы можете установить тип носителя для ResponseEntity.

return ResponseEntity.status(httpError.getStatus().value())
        .contentType(MediaType.APPLICATION_XML)
        .body(httpError);
...