简体   繁体   English

MVC-当自定义内容类型时接受JSON(不是application / json)

[英]MVC - Accept JSON when content-type is custom (not application/json)

I am trying to implement the Content-Security-Policy-Report-Only Header for my website. 我正在尝试为我的网站实施Content-Security-Policy-Report-Only标头。 In order to do that, i need a controller that will accept the browsers POST-Request - which will send data about the violation in form of JSON. 为了做到这一点,我需要一个控制器来接受浏览器的POST-Request-将以JSON的形式发送有关违规的数据。 This request, however, seems to specify the Content-Type as application/csp-report instead of application/json (side note: Why the hell??). 但是,此请求似乎将Content-Type指定为application/csp-report而不是application/json (附带说明:为何如此?)。

This apparently causes Spring to refuse the request - it seems like the usage of @RequestBody makes spring only accept requests that are of Content-Type "application/json" . 这显然导致Spring拒绝请求-似乎@RequestBody的使用使spring仅接受Content-Type "application/json"请求。 Even when i specifically set the value consumes of the @RequestMapping annotation to application/csp-report it still does not accept the request. 即使我专门将@RequestMapping批注的值consumes设置为application/csp-report它仍然不接受请求。

I have gone as far as using a filter to wrap the request with HttpServletRequestWrapper - which seems to be the common way of modifying the behavior of a request. 我已经尽可能使用HttpServletRequestWrapper过滤器包装请求-这似乎是修改请求行为的常用方法。 I have overwritten all of these methods: getContentType() , getHeader(String) , getHeaders(String) to return "application/json". 我已经覆盖了所有这些方法: getContentType()getHeader(String)getHeaders(String)返回“ application / json”。 But the request still does not go through. 但是请求仍然没有通过。

  • What am i missing here? 我在这里想念什么?
  • Are there any better solutions to this that do not require me to do magic with the request? 有没有更好的解决方案,这些解决方案不需要我根据请求做魔术呢?
  • I wouldn't even mind parsing the JSON manually, can i somehow accept it as plain String instead? 我什至不介意手动解析JSON,我可以以某种方式将其接受为纯字符串吗?

According documentation on @RequestBody annotation, 根据有关@RequestBody注释的文档,

The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request 请求的主体通过HttpMessageConverter传递,以根据请求的内容类型解析方法参数

What that means is Spring Framework defines a specialized API for defining how certain MediaTypes are converted into certain Java types when used as parameters to REST endpoints. 这意味着Spring Framework定义了一个专门的API,用于定义将某些MediaType用作REST端点的参数时如何将其转换为某些Java类型。

Here is a pretty good article showcasing these capabilities. 是一篇很好的文章,展示了这些功能。

There are a great deal of builtin Spring converters that you may be able to just configure and use if your media format can be mapped to their respective media formats. 如果可以将媒体格式映射到各自的媒体格式,则可以配置和使用大量内置的Spring转换器。 Specifically for your case, you should look at one of the converters available in spring.converter.json package. 专门针对您的情况,您应该查看spring.converter.json包中可用的转换器之一。 In simplest case, making it work should be as simple as: 在最简单的情况下,使其正常工作应如下所示:

HttpMessageConverter converter = new <JsonConverterOfYourChoice>(JsonMapper);

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

And then registering such converter into a spring's configuration as you do. 然后像您一样将这种转换器注册到弹簧的配置中。

Other available converter types include: 其他可用的转换器类型包括:

  • StringHttpMessageConverter StringHttpMessageConverter
  • ObjectToStringHttpMessageConverter (if you have already configured Spring's ConversionService to read your desired types from String) ObjectToStringHttpMessageConverter(如果您已经配置了Spring的ConversionService从String读取所需的类型)
  • ByteArrayHttpMessageConverter ByteArrayHttpMessageConverter
  • FormHttpMessageConverter FormHttpMessageConverter
  • Various XML-based converters living in spring.converter.xml package spring.converter.xml包中包含各种基于XML的转换器
  • AllEncompassingFormHttpMessageConverter (converter built on top of Form converter and capable of handling XML and JSON as well) AllEncompassingFormHttpMessageConverter(基于表单转换器构建的转换器,也能够处理XML和JSON)
  • Protobuf HttpMessageConverter Protobuf HttpMessageConverter
  • Atom/RSS feed message converters. Atom / RSS提要消息转换器。

Finally, if none of the above does not apply for you, you can make and register your own HttpMessageConverter implementation. 最后,如果以上都不适合您,则可以制作并注册自己的HttpMessageConverter实现。

Building M. Prokhorov's answer into a complete snippet, this code worked for me to add application/csp-report as a JSON message converter (using Jackson) in Spring Boot: M.Prokhorov的答案构建成完整的代码段,此代码对我application/csp-report ,它可以在Spring Boot中将application/csp-report添加为JSON消息转换器(使用Jackson):

@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);
    }
  };
}

The other answers helper me figuring out what was going on with @ResponseBody . 其他答案可以帮助我弄清楚@ResponseBody发生了什么。

CSP reporting is still relatively new and not quite standardized among browsers: CSP报告仍然相对较新,并且在浏览器之间还不够标准化:

The CSP2 spec states that CSP report requests need to use a content-type header of application/csp-report. CSP2规范指出,CSP报告请求需要使用application / csp-report的内容类型标头。 In my sample, I observed four different content-type headers: 在我的样本中,我观察到了四个不同的内容类型标头:

 application/x-www-form-urlencoded application/json application/csp-report application/json; charset=UTF-8 

What to Expect When Expecting Content Security Policy Reports 期待内容安全策略报告时的期望

So an alternative, to accept any kind of content type, is to read the input stream directly from the HttpServletRequest instead of using @ReponseBody with a message converter. 因此,接受任何一种内容类型的替代方法是直接从HttpServletRequest读取输入流,而不是将@ReponseBody与消息转换器一起使用。

For example, in Kotlin: 例如,在Kotlin中:

@PostMapping(path = [CSP_REPORT_URL])
fun reportFrontendError(
    request: HttpServletRequest
): ResponseEntity<Void> {
    val body = request.inputStream.bufferedReader().use { it.readText() }

    // ...

    return ResponseEntity(HttpStatus.OK)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否需要httpPost.setHeader(“ Accept”,“ application / json”)和httpPost.setHeader(“ Content-type”,“ application / json”)? - Are httpPost.setHeader(“Accept”, “application/json”) and httpPost.setHeader(“Content-type”, “application/json”) required? 在 Spring 中读取 Content-Type 应用程序/json - Reading Content-Type application/json in Spring 没有为Content-Type定义解析器:application / json - No parser defined for Content-Type: application/json RESTEasy:找不到内容类型应用程序/json 类型的编写器 - RESTEasy: Could not find writer for content-type application/json type GET调用REST API,Accept为text / csv,content-Type为application / json。 应答的形式应该是什么? - GET call on REST API with Accept as text/csv and content-Type as application/json. In what format should the reponse be? 使用 Fetch API javascript 将 Content-Type 设置为 application/Json - set Content-Type to application/Json using Fetch API javascript PlayFramework使用content-type application / json返回BadRequest - PlayFramework returns BadRequest with content-type application/json JAVA-处理针对Content-Type的HttpClient请求:application / json - JAVA - Process HttpClient request for Content-Type: application/json 我如何设置 Content-Type 以响应 application/json - How I can set Content-Type in react to application/json 将表单数据部分中的 Content-Type 指定为 application/json - Specify Content-Type in form-data part as application/json
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM