MVC-принимает JSON, когда тип контента является пользовательским (не application/json)


Я пытаюсь реализовать заголовок Content-Security-Policy-Report-Only для моего веб-сайта. Для этого мне нужен контроллер, который будет принимать пост-запрос браузеров - который будет отправлять данные о нарушении в виде JSON. Этот запрос, однако, похоже, указывает тип контента как application/csp-report вместо application/json (Примечание сбоку: Какого черта??).

Это, по-видимому, заставляет Spring отклонять запрос - похоже, что использование @RequestBody заставляет spring принимать только те запросы, которые типа содержания "application/json". Даже когда я специально устанавливаю значение consumes аннотации @RequestMapping в application/csp-report, он все равно не принимает запрос.

Я зашел так далеко, что использовал фильтр для обертывания запроса с помощью HttpServletRequestWrapper, что, по - видимому, является обычным способом изменения поведения запроса. Я переписал все эти методы: getContentType(), getHeader(String), getHeaders(String) вернуть "application/json". Но запрос все равно не проходит.

  • чего мне здесь не хватает?
  • Есть ли любые лучшие решения для этого, что не требуется ли от меня колдовать с просьбой?
  • я бы даже не стал разум разбирает JSON вручную, могу ли я как-то принять его как простой Вместо веревки?
2 3

2 ответа:

Согласно документации по @RequestBody аннотации,

Тело запроса передается через HttpMessageConverter для разрешения аргумента метода в зависимости от типа содержимого запроса

Это означает, что Spring Framework определяет специализированный API для определения того, как определенные типы носителей преобразуются в определенные типы Java при использовании в качестве параметров для конечных точек REST.

Вот довольно хорошая статья, демонстрирующая эти способности.

Существует большое количество встроенных преобразователей Spring, которые вы можете просто настроить и использовать, если ваш формат мультимедиа может быть сопоставлен с их соответствующими форматами мультимедиа. Специально для вашего случая вам стоит посмотреть на один из конвертеров, доступных в spring.конвертер.JSON пакет. В простейшем случае заставить его работать должно быть так же просто, как:

HttpMessageConverter converter = new <JsonConverterOfYourChoice>(JsonMapper);

converter.getSupportedMediaTypes().add(new MediaType("application", "csp-report"));

А затем регистрируем такой преобразователь в конфигурацию пружины, как это делаете вы.

Другие доступные типы конвертеров включают:

  • StringHttpMessageConverter
  • ObjectToStringHttpMessageConverter (если вы уже настроили Spring ConversionService для чтения нужных типов из строки)
  • ByteArrayHttpMessageConverter
  • FormHttpMessageConverter
  • различные XML-конвертеры, живущие в spring.конвертер.xml пакет
  • AllEncompassingFormHttpMessageConverter (конвертер, построенный поверх преобразователя формы и способен обрабатывать XML и JSON, а также)
  • Protobuf HttpMessageConverter
  • Atom/RSS конвертеры сообщений канала.

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

Построение ответа М. Прохорова в полный фрагмент, этот код работал для меня, чтобы добавить application/csp-report в качестве конвертера сообщений JSON (используя Jackson) в Spring Boot:

@Bean
public WebMvcConfigurer webMvcConfigurer() {
  return new WebMvcConfigurerAdapter() {
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
      super.extendMessageConverters(converters);

      final List<MediaType> cspReportMediaTypes =
          Collections.singletonList(new MediaType("application", "csp-report"));

      final HttpMessageConverter<Object> cspReportConverter =
          new MappingJackson2HttpMessageConverter() {
            @Override
            public List<MediaType> getSupportedMediaTypes() {
              return cspReportMediaTypes;
            }
          };

      converters.add(cspReportConverter);
    }
  };
}