[英]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. 但是请求仍然没有通过。
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: 其他可用的转换器类型包括:
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.