requestmapping 參數沒設置好 導致返回的protobuf解析報錯

背景:使用protobuf2做與前端的數據交互,自己用junit測試的時候沒問題,但是前端人員訪問接口,總是報錯:
com.google.protobuf.InvalidProtocolBufferException: Protocol message end-group tag did not match expected tag.

剛開始以爲是protobuf jar包版本不一致導致的問題,後來自己用不同版本的protobuf訪問接口也沒問題。找啊找都沒找到問題出在哪兒,後來前端的同學說正常應該返回二進制數據,但是我們返回的是個string,根據這個點找到了問題。

結果就是:接口沒指定返回的數據類型,

RequestMapping("api/getC")改成  @RequestMapping(value = "api/getC", produces = "application/x-protobuf").

問題解決後,回去看爲什麼自己寫的junitTest沒問題,然後發現有指定accept,如圖153行代碼:

,當我刪掉produces配置再把153行刪掉,果然報錯了。

後記1:

produces :指定返回值類型,還設定返回值的字符編碼;對應header裏面的Accept;

consumes:指定處理請求的提交內容類型;對應header裏面的Content-Type);

後記2: 查詢資料過程中,又在思考,框架是怎麼根據這些參數去返回數據的呢。這裏是spring的HttpMessageConverter這個類起作用的,springmvc默認會加載StringHttpMessageConverter、ByteArrayHttpMessageConverter等,配置如圖。


@Configuration
public class SpringMVCConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
        stringConverter.setDefaultCharset(Charsets.UTF_8);
        stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.parseMediaType("text/plain;charset=UTF-8")));
        converters.add(stringConverter);

        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        fastConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON_UTF8));
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(fastConverter);

        converters.add(new ProtobufHttpMessageConverter());
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new HeaderArgumentResolver());
    }
}

mvc會根據request中的content-type,遍歷messageConverters中的converter,如果(targetClass != null && converter.canRead(targetClass, contentType))==true 說明找到了對應的轉換器,如果debug模式可以看到如下日誌:

Read [class com.cc.apply.QueryRequest] as "application/x-protobuf;charset=UTF-8" with [org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter@20413045]

canRead方法調用的其實是 AbstractHttpMessageConverter的canRead方法:

public boolean canRead(Class<?> clazz, MediaType mediaType) {
    return this.supports(clazz) && this.canRead(mediaType);
}

返回的時候調用AbstractHttpMessageConverter的canWrite方法,確定適用的轉換器爲protobuf,writeIternal()

找到一篇把整個流程寫的比較清楚的:https://blog.csdn.net/everyok/article/details/81350894 留看

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章