美文网首页
RestTemplate 抓包及使用

RestTemplate 抓包及使用

作者: 北海北_6dc3 | 来源:发表于2020-02-21 22:42 被阅读0次

    配置

    定义bean方式一

    @Configuration
    public class SpringConfig {
        @Bean
        public RestTemplate getRestTemplate() {
            System.setProperty("http.proxyHost", "127.0.0.1");
            System.setProperty("http.proxyPort", "8888");
            HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
            int mseconds = Integer.valueOf(8000);
            httpRequestFactory.setConnectionRequestTimeout(mseconds);
            httpRequestFactory.setConnectTimeout(mseconds);
            httpRequestFactory.setReadTimeout(mseconds);
            return new RestTemplate(httpRequestFactory);
        }
    }
    

    定义bean方式二

    @Configuration
    public class SpringConfig {
        @Bean
        public RestTemplate getRestTemplate() {
            RestTemplate restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory() {{
                setProxy(new java.net.Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8888)));
            }});
            return restTemplate;
        }
    }
    

    说明:设置代理8888是为了fiddler抓包。
    参见:
    https://www.okcode.net/article/47473

    那么我们第一种和第二种定义有什么区别尼?

    ClientHttpRequestFactory接口主要提供了两种实现方式

    • 一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接HttpURLConnection,默认使用此方式。
    • 一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。

    参见:
    https://stackoverflow.com/questions/25698072/simpleclienthttprequestfactory-vs-httpcomponentsclienthttprequestfactory-for-htt
    https://juejin.im/entry/5b21c6d55188257d9b79e1e8

    By default RestTemplate uses SimpleClientHttpRequestFactory which depends on default configuration of HttpURLConnection.
    If you want to use HttpComponentsClientHttpRequestFactory - it has a connection pooling configuration which SimpleClientHttpRequestFactory does not have.

    model定义

    @Data
    public class AuthInfo implements Serializable {
        private String CSPID;
        private String UserID;
        private String ContentID;
        private String ProductID;
        private String ServiceID;
        private String Token;
    }
    

    调用

        public String auth(AuthInfo authInfo) {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            //如果对方返回类型不为json,不加这句话,会报404错误。
            headers.set("Accept","*/*");
            HttpEntity<AuthInfo> entity = new HttpEntity<AuthInfo>(authInfo, headers);
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(authUrl, entity, String.class);
            String result = responseEntity.getBody();
            System.out.println(result);
            return result;
        }
    

    坑1:对方返回类型为Content-Type: text/html; charset=UTF-8,如果accept类型不匹配,会报404,故,需要增加headers.set("Accept","/");
    坑2:参数要求首字母大写。如定义。
    要求格式:

    {
        "CSPID": 2316,
        "ContentID": "asdf",
        "ProductID": "asfs",
        "UserID": "sdfs",
        "Token": "sfss",
        "ServiceID":"20171902141"
    }
    

    我们序列化的格式

    {
        "cspid": 2316,
        "contentID": "asdf",
        "productID": "asfs",
        "userID": "sdfs",
        "token": "sfss",
        "serviceID":"20171902141"
    }
    

    如何处理参数大写问题?

    首先我们需要确认,restTemplate使用的什么序列化json.
    消息转换核心代码

            //getMessageConverters()获取消息转换 的方法
            for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {
                if (messageConverter instanceof GenericHttpMessageConverter) {
                    GenericHttpMessageConverter<Object> genericMessageConverter = (GenericHttpMessageConverter<Object>) messageConverter;
                    if (genericMessageConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) {
                       .......
                        genericMessageConverter.write(
                                requestBody, requestBodyType, requestContentType, httpRequest);
                        return;
                    }
                }
                else if (messageConverter.canWrite(requestBodyClass, requestContentType)) {
                     .....
                }
            }
    
    
    
        //messageConverters包含的转换器
        public List<HttpMessageConverter<?>> getMessageConverters() {
            return this.messageConverters;
        }
        //messageConverters初始化
        public RestTemplate() {
            this.messageConverters.add(new ByteArrayHttpMessageConverter());
            this.messageConverters.add(new StringHttpMessageConverter());
            this.messageConverters.add(new ResourceHttpMessageConverter());
            this.messageConverters.add(new SourceHttpMessageConverter<Source>());
            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());
            }
        }
    
        //加载jackson2Present 的条件
        private static final boolean jackson2Present =
                ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
                        RestTemplate.class.getClassLoader()) &&
                ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
                        RestTemplate.class.getClassLoader());
    
        //成功加载,即为成功。
        public static boolean isPresent(String className, ClassLoader classLoader) {
            try {
                forName(className, classLoader);
                return true;
            }
            catch (Throwable ex) {
                // Class or one of its dependencies is not present...
                return false;
            }
        }
    

    以下是messageConverters运行时 包含的对象.

    image.png

    我们可以看到,消息转换器默认使用的是jackson2。
    所以我们需要使用@JsonProperty
    参见:
    https://blog.csdn.net/qingguiyu/article/details/79215448
    使用后和@Data使用,发现会生成多份数据。需要移除@Data,将@JsonProperty放到get方法上。
    参见:
    https://blog.csdn.net/weixin_41450959/article/details/87691788

    其他一些技巧:
    https://www.cnblogs.com/soul-wonder/p/8890728.html
    连接池信息
    https://juejin.im/post/5d2c72cde51d4555fd20a3f6

    相关文章

      网友评论

          本文标题:RestTemplate 抓包及使用

          本文链接:https://www.haomeiwen.com/subject/bmxhqhtx.html