Spring Boot Controller可以接收纯文本吗?

时间:2019-09-17 09:10:54

标签: java spring rest spring-boot

我正在尝试使用纯文本主体(utf-8)处理POST请求,但似乎spring不喜欢该调用的纯文本性质。可能是它不受支持吗?否则,我编码是否错误?

@RestController
@RequestMapping(path = "/abc", method = RequestMethod.POST)
public class NlpController {
    @PostMapping(path= "/def", consumes = "text/plain; charset: utf-8", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Object> doSomething(@RequestBody String bodyText)
    {
        ...
        return ResponseEntity.ok().body(responseObject);
    }
}

回复为:

已解决的[org.springframework.web.HttpMediaTypeNotSupportedException:不支持内容类型'application / x-www-form-urlencoded'

我使用curl命令进行了测试:

curl -s -X POST -H 'Content-Type: text/plain; charset: utf-8' --data-binary @text.txt localhost:8080/abc/def

text.txt包含纯文本(希伯来语为UTF-8)。

3 个答案:

答案 0 :(得分:1)

在弹簧是否支持文本/纯文本的问题的另一部分,我想作一些阐述。

根据spring文档: @RequestMapping 批注

中的“消费”或“消耗性媒体类型”是什么

定义:

耗材类型

“您可以通过指定消耗性媒体类型的列表来缩小主映射的范围。仅当Content-Type请求标头与指定的媒体类型匹配时,请求才会被匹配。例如:”

@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // implementation omitted
}

也可以像在!text / plain中一样否定消耗性媒体类型表达式,以匹配除Content / Type为text / plain的请求以外的所有请求。

介质类型在内部如何匹配?

Spring请求驱动设计围绕一个称为调度程序Servlet的Servlet进行,该Servlet使用特殊的Bean来处理请求,其中一个Bean是RequestMappingHandlerMapping,它使用以下命令检查媒体类型 ConsumesRequestCondition类的getMatchingCondition方法,如下所示。

    @Override
    public ConsumesRequestCondition getMatchingCondition(ServerWebExchange exchange) {
        if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
            return PRE_FLIGHT_MATCH;
        }
        if (isEmpty()) {
            return this;
        }
        Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>(expressions);
        result.removeIf(expression -> !expression.match(exchange));
        return (!result.isEmpty() ? new ConsumesRequestCondition(result) : null);
    }

获取匹配条件类使用静态内部类ConsumesMediaType Expression,它实际上进行了检查

     @Override
     protected boolean matchMediaType(ServerWebExchange exchange) throws UnsupportedMediaTypeStatusException {
    try {
        MediaType contentType = exchange.getRequest().getHeaders().getContentType();
        contentType = (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
        return getMediaType().includes(contentType);
    }
    catch (InvalidMediaTypeException ex) {
        throw new UnsupportedMediaTypeStatusException("Can't parse Content-Type [" +
                exchange.getRequest().getHeaders().getFirst("Content-Type") +
                "]: " + ex.getMessage());
    }}

一旦媒体类型不匹配,此方法将返回false,并且getMatchingCondition返回null,这将导致调用RequestMappingInfoHandlerMapping的handleNoMatch方法,并使用PartialMatchHelper类检查如下所示的不匹配类型,并一旦抛出HttpMediaTypeNotSupportedException错误就抛出弹簧看到消耗不匹配

if (helper.hasConsumesMismatch()) {
        Set<MediaType> mediaTypes = helper.getConsumableMediaTypes();
        MediaType contentType = null;
        if (StringUtils.hasLength(request.getContentType())) {
            try {
                contentType = MediaType.parseMediaType(request.getContentType());
            }
            catch (InvalidMediaTypeException ex) {
                throw new HttpMediaTypeNotSupportedException(ex.getMessage());
            }
        }
        throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes));
    }

Spring根据IANA https://www.iana.org/assignments/media-types/media-types.xhtml支持所有媒体类型,问题仅出在别人引用的curl命令上。

答案 1 :(得分:0)

@rumbz 请参考以下链接,它可能会解决您的问题

Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for @RequestBody MultiValueMap

1使用注释

@RequestMapping(value = "/some-path", produces = 
org.springframework.http.MediaType.TEXT_PLAIN)    
public String plainTextAnnotation() {    
    return "<response body>";    
}

其中,将/ some-path替换为您要使用的任何内容。

2在响应实体的HTTP标头中设置内容类型:

public String plainTextResponseEntity() {    
     HttpHeaders httpHeaders = new HttpHeaders();    

     httpHeaders.setContentType(org.springframework.http.MediaType.TEXT_PLAIN);    
     return new ResponseEntity("<response body>", httpHeaders, HttpStatus.OK);    
}  

答案 2 :(得分:0)

每个@ m-deinum的评论:问题不在spring框架中-而是curl在请求中添加了“ application / x-www-form-urlencoded”的事实...

为了使这个问题更完整:

curl -s -X POST -H "Content-Type:" -H "Content-Type: text/plain; charset: utf-8" --data-binary @file.txt localhost:8080/abc/def