• 【原创】大叔问题定位分享(34)Spring的RestTemplate请求json数据后内容被修改


    先看代码

    org.springframework.web.client.RestTemplate

        public RestTemplate() {
            this.messageConverters = new ArrayList();
            this.errorHandler = new DefaultResponseErrorHandler();
            this.headersExtractor = new RestTemplate.HeadersExtractor();
            this.messageConverters.add(new ByteArrayHttpMessageConverter());
            this.messageConverters.add(new StringHttpMessageConverter());
            this.messageConverters.add(new ResourceHttpMessageConverter(false));
    
            try {
                this.messageConverters.add(new SourceHttpMessageConverter());
            } catch (Error var2) {
                ;
            }
    
            this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
            if(romePresent) {
                this.messageConverters.add(new AtomFeedHttpMessageConverter());
                this.messageConverters.add(new RssChannelHttpMessageConverter());
            }
    
            if(jackson2XmlPresent) {
                this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
            } else if(jaxb2Present) {
                this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
            }
    
            if(jackson2Present) {
                this.messageConverters.add(new MappingJackson2HttpMessageConverter());
            } else if(gsonPresent) {
                this.messageConverters.add(new GsonHttpMessageConverter());
            } else if(jsonbPresent) {
                this.messageConverters.add(new JsonbHttpMessageConverter());
            }
    
            if(jackson2SmilePresent) {
                this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
            }
    
            if(jackson2CborPresent) {
                this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
            }
    
            this.uriTemplateHandler = initUriTemplateHandler();
        }

    构造函数中会根据各种boolean标志添加很多MessageConverter,而这些boolean标志来自

        static {
            ClassLoader classLoader = RestTemplate.class.getClassLoader();
            romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
            jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
            jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
            jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
            jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
            jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
            gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
            jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
        }

    在发请求时

        public <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException {
            RequestCallback requestCallback = this.httpEntityCallback(request, responseType);
            ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
            return (ResponseEntity)nonNull(this.execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables));
        }

    会创建一个ResponseExtractor

        private class ResponseEntityResponseExtractor<T> implements ResponseExtractor<ResponseEntity<T>> {
            @Nullable
            private final HttpMessageConverterExtractor<T> delegate;
    
            public ResponseEntityResponseExtractor(@Nullable Type responseType) {
                if(responseType != null && Void.class != responseType) {
                    this.delegate = new HttpMessageConverterExtractor(responseType, RestTemplate.this.getMessageConverters(), RestTemplate.this.logger);
                } else {
                    this.delegate = null;
                }
    
            }

    可见是根据responseType创建了一个代理,然后代理中包含了所有添加过的MessageConverter

    而在execute中会调用

        protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
            Assert.notNull(url, "URI is required");
            Assert.notNull(method, "HttpMethod is required");
            ClientHttpResponse response = null;
    
            Object var14;
            try {
                ClientHttpRequest request = this.createRequest(url, method);
                if(requestCallback != null) {
                    requestCallback.doWithRequest(request);
                }
    
                response = request.execute();
                this.handleResponse(url, method, response);
                var14 = responseExtractor != null?responseExtractor.extractData(response):null;

    即responseExecutor.extractData,来看下这个函数

        public T extractData(ClientHttpResponse response) throws IOException {
            MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
            if(responseWrapper.hasMessageBody() && !responseWrapper.hasEmptyMessageBody()) {
                MediaType contentType = this.getContentType(responseWrapper);
    
                try {
                    Iterator var4 = this.messageConverters.iterator();
    
                    while(var4.hasNext()) {
                        HttpMessageConverter<?> messageConverter = (HttpMessageConverter)var4.next();
                        if(messageConverter instanceof GenericHttpMessageConverter) {
                            GenericHttpMessageConverter<?> genericMessageConverter = (GenericHttpMessageConverter)messageConverter;
                            if(genericMessageConverter.canRead(this.responseType, (Class)null, contentType)) {
                                if(this.logger.isDebugEnabled()) {
                                    ResolvableType resolvableType = ResolvableType.forType(this.responseType);
                                    this.logger.debug("Reading to [" + resolvableType + "]");
                                }
    
                                return genericMessageConverter.read(this.responseType, (Class)null, responseWrapper);
                            }
                        }
    
                        if(this.responseClass != null && messageConverter.canRead(this.responseClass, contentType)) {
                            if(this.logger.isDebugEnabled()) {
                                String className = this.responseClass.getName();
                                this.logger.debug("Reading to [" + className + "] as "" + contentType + """);
                            }
    
                            return messageConverter.read(this.responseClass, responseWrapper);
                        }
                    }
                } catch (HttpMessageNotReadableException | IOException var8) {
                    throw new RestClientException("Error while extracting response for type [" + this.responseType + "] and content type [" + contentType + "]", var8);
                }
    
                throw new RestClientException("Could not extract response: no suitable HttpMessageConverter found for response type [" + this.responseType + "] and content type [" + contentType + "]");
            } else {
                return null;
            }
        }

    所以当你发现使用RestTemplate发请求后数据被修改的时候,要检查相应的content type,要检查RestTemplate中有哪些MessageConverter(包括各个boolean标志),

    如果确定数据不需要被修改时,可以调用RestTemplate.setMessageConverters方法,传入默认的StringHttpMessageConverter即可;

  • 相关阅读:
    『轉』windows文件的占用空间与文件大小
    『轉』asterisk入门连载二
    vm系統出現This Virtual Machine Appears To Be In Use的問題
    linux 7788
    鸿蒙开发板外设控制 之 实现按键“按下事件”和“释放事件”的通用框架(V0.0.1)
    【开发板试用报告】学习GPIO编程
    前言「HarmonyOS应用开发基础篇」
    【开发板试用报告】鸿蒙OS环境搭建及代码烧录
    动态设置和访问cxgrid列的Properties
    cxgrid导出excel
  • 原文地址:https://www.cnblogs.com/barneywill/p/11141164.html
Copyright © 2020-2023  润新知