gpt4 book ai didi

spring-boot - Spring Boot MVC 允许在 Controller 中使用任何类型的内容

转载 作者:行者123 更新时间:2023-12-04 17:38:50 24 4
gpt4 key购买 nike

我有一个 RestController,多个合作伙伴使用它来发送 XML 请求。然而,这是一个传给我的遗留系统,最初的实现是在 PHP 中以非常松散的方式完成的。

这允许客户发送不同的content-types(application/xmltext/xml, application/x-www-form-urlencoded) 它让我需要支持许多 MediaTypes 以避免返回 415 MediaType不支持的错误。

我在配置类中使用了以下代码来允许多种媒体类型。

@Bean
public MarshallingHttpMessageConverter marshallingMessageConverter() {
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter();
converter.setMarshaller(jaxbMarshaller());
converter.setUnmarshaller(jaxbMarshaller());
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML,
MediaType.TEXT_XML, MediaType.TEXT_PLAIN, MediaType.APPLICATION_FORM_URLENCODED, MediaType.ALL));
return converter;
}

@Bean
public Jaxb2Marshaller jaxbMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(CouponIssuedStatusDTO.class, CouponIssuedFailedDTO.class,
CouponIssuedSuccessDTO.class, RedemptionSuccessResultDTO.class, RedemptionResultHeaderDTO.class,
RedemptionFailResultDTO.class, RedemptionResultBodyDTO.class, RedemptionDTO.class, Param.class,
ChannelDTO.class, RedeemRequest.class);
Map<String, Object> props = new HashMap<>();
props.put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setMarshallerProperties(props);
return marshaller;
}

Controller 方法是这样的:

@PostMapping(value = "/request", produces = { "application/xml;charset=UTF-8" }, consumes = MediaType.ALL_VALUE)
public ResponseEntity<RedemptionResultDTO> request(
@RequestHeader(name = "Content-Type", required = false) String contentType,
@RequestBody String redeemRequest) {
return requestCustom(contentType, redeemRequest);

}

此端点被所有客户端访问。这只是最后一个客户给我带来麻烦。他们正在发送 content-type = application/x-www-form-urlencoded; charset=65001 (UTF-8)": 65001 (UTF-8)

由于字符集的发送方式,Spring Boot 拒绝返回除 415 以外的任何内容。甚至 MediaType.ALL 似乎都没有任何效果。

有没有办法让 Spring 允许我忽略内容类型?创建过滤器和更改内容类型是不可行的,因为 HttpServletRequest 不允许改变内容类型。我没有想法,但我真的认为必须有一种方法来允许自定义内容类型。

更新

如果我删除 @RequestBody,那么我不会收到错误 415,但我无法获取请求正文,因为 HttpServletRequest 到达 Controller 操作时为空。

最佳答案

最好的情况是从 RequestMapping 构造函数中删除 consumes 参数。添加它的那一刻,spring 将尝试将其解析为已知类型 MediaType.parseMediaType(request.getContentType()) 并尝试创建一个 new MimeType(type, subtype, parameters ) 并因传递的字符集格式无效而抛出异常。

但是,如果您删除了 consumes,并且您想要验证/限制传入的 Content-Type 为特定类型,您可以注入(inject) HttpServletRequest 在你的方法中作为参数,然后检查 request.getHeader(HttpHeaders.CONTENT_TYPE) 的值。

您还必须删除 @RequestBody 注释,这样 Spring 就不会尝试解析内容类型来解码正文。如果您直接尝试在此处读取 request.getInputStream()request.getReader(),您将看到 null,因为流已被 Spring 读取。因此,要访问输入内容,请使用 spring 的 ContentCachingRequestWrapper 通过 Filter 注入(inject),然后您可以在缓存内容时重复读取内容,而不是从原始流中读取内容。

我在这里包含一些代码片段以供引用,但是要查看可执行示例,您可以引用我的 github repo 。它是一个带有 maven 的 spring-boot 项目,一旦你启动它,你可以将你的帖子请求发送到 http://localhost:3007/badmedia & 它会在响应中反射(reflect)你 request content-type & body。希望这会有所帮助。

@RestController
public class BadMediaController {

@PostMapping("/badmedia")
@ResponseBody
public Object reflect(HttpServletRequest request) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.createObjectNode();
((ObjectNode) rootNode).put("contentType", request.getHeader(HttpHeaders.CONTENT_TYPE));
String body = new String(((ContentCachingRequestWrapper) request).getContentAsByteArray(), StandardCharsets.UTF_8);
body = URLDecoder.decode(body, StandardCharsets.UTF_8.name());
((ObjectNode) rootNode).put("body", body);
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
}
}


@Component
public class CacheRequestFilter extends GenericFilterBean {

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest cachedRequest
= new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);
//invoke caching
cachedRequest.getParameterMap();
chain.doFilter(cachedRequest, servletResponse);
}
}

关于spring-boot - Spring Boot MVC 允许在 Controller 中使用任何类型的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55482593/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com