[英]HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
[英]Spring Boot - Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
我使用的是最新的 Spring Boot 版本,目前是 2.2.2-RELEASE。
我有这个端点:
@RequestMapping(method = RequestMethod.POST, value = "/test", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<?> post(@RequestParam(required = false) MultiValueMap<?, ?> paramMap) throws Exception {
// CODE
return new ResponseEntity<>(HttpStatus.OK);
}
如果我调用它(来自邮递员)将正文设置为 x-www-form.urlencoded 一切都很好,我会收到 200 OK 状态代码。
但是,如果我修改上述端点(添加另一个参数)如下:
@RequestMapping(method = RequestMethod.POST, value = "/test", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<?> post(@RequestParam(required = false) MultiValueMap<?, ?> paramMap, RequestEntity<?> req) throws Exception {
// CODE
return new ResponseEntity<>(HttpStatus.OK);
}
我收到此错误:
{
"timestamp": 1576961587242,
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported",
"path": "/test"
}
缺了点什么?
先感谢您。
正如@Sunil Dabburi 建议调试AbstractMessageConverterMethodArgumentResolver
的readWithMessageConverters
方法揭示了这个问题,一旦理解它就会变得非常简单。 Spring 有大约 15 个默认消息转换器,它们负责将传入请求的内容转换为RequestEntity
或HttpEntity
。 如果请求有正文,转换器会读取它并将其转换为它负责的对象类型。 根据传入请求的媒体类型,每个转换器决定它是否可以读取请求。 在application/x-www-form-urlencoded
媒体类型的情况下,没有一个默认的 Spring 转换器可以处理这样的请求。 因此,会出现上述错误。
将application/x-www-form-urlencoded
媒体类型的自定义转换器添加到 Spring 的 http 消息转换器列表将解决该问题。 在下面的示例中,自定义转换器仅负责读取请求,并且仅负责具有所需媒体类型的请求。
** 这些读取有助于理解媒体类型本身以及 spring 如何使用它,因此自定义转换器应该如何转换传入的请求:
以下是此类自定义 http 消息转换器的示例:
@Component
public class FormUrlencodedHttpMessageConverter extends
AbstractGenericHttpMessageConverter<MultiValueMap<String, String>> {
private static final MediaType CONVERTER_MEDIA_TYPE = MediaType.APPLICATION_FORM_URLENCODED;
public FormUrlencodedHttpMessageConverter() {
super(CONVERTER_MEDIA_TYPE);
}
@Override
public MultiValueMap<String, String> read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
String urlEncodedData = new BufferedReader(
new InputStreamReader(inputMessage.getBody(), StandardCharsets.UTF_8)).readLine();
String[] keyValuePairs = urlEncodedData.split("&");
MultiValueMap<String, String> keyValuePairsMap = new LinkedMultiValueMap<>();
for (String keyValuePair : keyValuePairs) {
String[] pairElements = keyValuePair.split("=");
String key = pairElements[0];
String value = pairElements[1];
keyValuePairsMap.add(key, value);
}
return keyValuePairsMap;
}
@Override
protected boolean canRead(@Nullable MediaType mediaType) {
return CONVERTER_MEDIA_TYPE.includes(mediaType);
}
@Override
protected boolean canWrite(@Nullable MediaType mediaType) {
return CONVERTER_MEDIA_TYPE.includes(mediaType);
}
@Override
protected void writeInternal(MultiValueMap<String, String> t, Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
throw new RuntimeException("Method 'writeInternal' in " + this.getClass().getSimpleName() + " is not implemented");
}
@Override
protected MultiValueMap<String, String> readInternal(Class<? extends MultiValueMap<String, String>> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
throw new RuntimeException("Method 'readInternal' in " + this.getClass().getSimpleName() + " is not implemented");
}
经过大量搜索,我找到了很多材料,但我不喜欢所提出的解决方案。
所以我决定尝试不同的方法。
在我开发此代码的那一刻,自动装配HttpServletRequest
我能够访问所有所需的值,如标头、正文、参数。 所以我开始拦截它,然后我创建了我定制的HttpEntity
。
如果有人遇到同样的问题,这里是代码,请随时提出修改和改进建议。
@RequestMapping(method = RequestMethod.POST, value = "/**", consumes = MediaType.ALL_VALUE, produces = MediaType.ALL_VALUE)
public ResponseEntity<?> post(HttpServletRequest servletRequest) throws Exception {
String url = servletRequest.getRequestURI().replaceFirst("/", "");
HttpHeaders httpHeaders = (Collections
.list(servletRequest.getHeaderNames())
.stream()
.collect(Collectors.toMap(
Function.identity(),
h -> Collections.list(servletRequest.getHeaders(h)),
(oldValue, newValue) -> newValue,
HttpHeaders::new
))
);
HttpEntity<?> request;
String body = servletRequest.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
if (!body.isEmpty()) {
request = new HttpEntity<>(body, httpHeaders);
} else {
Map<String, String> payload = new HashMap<>();
Stream.of(servletRequest.getParameterMap()).forEach(stringMap -> stringMap.forEach((k, v) ->
Stream.of(v).forEach(value -> payload.put(k, value))
));
request = new HttpEntity<>(payload, httpHeaders);
}
return getSuccessResponse(proxyService.doProxyTest(request, url, new HttpPost(url)));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.