【原创】大叔问题定位分享(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即可;

原文地址:https://www.cnblogs.com/barneywill/p/11141164.html

时间: 2024-11-07 08:08:32

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

Spring使用fastjson处理json数据

1.搭建SpringMVC+spring环境 2.配置web.xml以及springmvc-config.xml,web.xml同Spring使用jackson处理json数据一样,Springmvc-config.xml有些许差别.Spring默认配置使用Jackson,如果要使用fastjson则需要配置HttpMessageConverter. <?xml version="1.0" encoding="UTF-8"?> <beans xml

Spring接收和响应json数据

一.前言 关于什么是json以及基本使用技巧,为什么使用json等等,这里不再重复,直接进入主题 注:服务端接收json数据还原为java对象,称为反序列化,反之,将java对象作为响应转换为json数据发回给客户端,称为序列化 二.导入json相关框架的依赖(比如jackson) 如果使用的是spring boot框架,导入spring boot相关依赖后,就存在相关依赖,无需重复,否则会报错:   如果使用的是spring MVC框架,就需要手动导入相关依赖(比如Jackson),直接上代码

【原创】大叔问题定位分享(29)datanode启动报错:50020端口被占用

集群中有一台datanode一直启动报错如下: java.net.BindException: Problem binding to [$server1:50020] java.net.BindException: Address already in use; For more details see: http://wiki.apache.org/hadoop/BindException 查看端口是否被占用 # netstat -tnlp|grep 50020 发现没有进程在监听50020端

【原创】大叔问题定位分享(33)oozie提交任务报错ArithmeticException: / by zero

oozie提交workflow后执行task报错: 2019-07-04 17:19:00,559 ERROR [RMCommunicator Allocator] org.apache.hadoop.mapreduce.v2.app.rm.RMContainerAllocator: ERROR IN CONTACTING RM. java.lang.ArithmeticException: / by zero at org.apache.hadoop.mapreduce.v2.app.rm.R

【原创】大叔问题定位分享(36)openresty(nginx+lua)中获取不到post数据,ngx.req.get_body_data返回nil

openresty(nginx+lua)中获取不到post数据,ngx.req.get_body_data返回nil This function returns nil if the request body has not been read, the request body has been read into disk temporary files, or the request body has zero size. 打开nginx调试日志 error_log /var/log/ng

【原创】问题定位分享(16)spark写数据到hive外部表报错ClassCastException: org.apache.hadoop.hive.hbase.HiveHBaseTableOutputFormat cannot be cast to org.apache.hadoop.hive.ql.io.HiveOutputFormat

spark 2.1.1 spark在写数据到hive外部表(底层数据在hbase中)时会报错 Caused by: java.lang.ClassCastException: org.apache.hadoop.hive.hbase.HiveHBaseTableOutputFormat cannot be cast to org.apache.hadoop.hive.ql.io.HiveOutputFormat at org.apache.spark.sql.hive.SparkHiveWrit

【原创】问题定位分享(18)beeline连接spark thrift有时会卡住

spark 2.1.1 beeline连接spark thrift之后,执行use database有时会卡住,而use database 在server端对应的是 setCurrentDatabase, 经过排查发现当时spark thrift正在执行insert操作, org.apache.spark.sql.hive.execution.InsertIntoHiveTable protected override def doExecute(): RDD[InternalRow] = {

【原创】问题定位分享(19)spark task在executors上分布不均

最近提交一个spark应用之后发现执行非常慢,点开spark web ui之后发现卡在一个job的一个stage上,这个stage有100000个task,但是绝大部分task都分配到两个executor上,其他executor非常空闲,what happened? 查看spark task分配逻辑发现,有一个data locality即数据本地性的特性,详见 https://www.cnblogs.com/barneywill/p/10152497.html即会按照locality级别的优先级

Spring 跨重定向请求传递数据

在处理完POST请求后, 通常来讲一个最佳实践就是执行一下重定向.除了其他的一些因素外,这样做能够防止用户点击浏览器的刷新按钮或后退箭头时,客户端重新执行危险的POST请求. 在控制器方法返回的视图名称中,我们借助了" redirect:" 前缀的力量.当控制器方法返回的String 值 以" redirect:" 开头 的 话, 那么 这个 String 不是 用来 查找 视图 的, 而是 用来 指导 浏览器 进行 重定向 的 路径. 我们 可以 回头 看一下 程