日常問題隨筆-RestTemplate發送Get請求通過body傳參問題

問題出現

今天在對接其他部門的接口時,發現對方提供了一個GET請求,但是參數卻要求通過body傳遞json格式的數據。這可難住我了,GET請求還能通過body傳遞參數嗎?帶着疑問,先試一下吧。我們項目用的RestTemplate,我想起了RestTemplate的exchange方法有個參數HttpEntity,會不會是這裏可以傳參數進去呢?迅速寫了代碼

public static String getForJson(String url, Map<String,Object> dataValue) {
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
    HttpEntity<String> httpEntity = new HttpEntity<>(JSON.toJSONString(dataValue),httpHeaders);
    return SpringContextUtil.getBean(RestTemplate.class).exchange(url, HttpMethod.GET,httpEntity,String.class).getBody();
}

結果

2020-06-18 17:08:37.544|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "GET /cross/appms-internal/v1/portal/app/config/search HTTP/1.1[\r][\n]"
2020-06-18 17:08:37.544|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept: text/plain, application/json, application/*+json, */*[\r][\n]"
2020-06-18 17:08:37.544|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
2020-06-18 17:08:37.544|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp[\r][\n]"
2020-06-18 17:08:37.547|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Host: [\r][\n]"
2020-06-18 17:08:37.547|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2020-06-18 17:08:37.547|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.10 (Java/1.8.0_201)[\r][\n]"
2020-06-18 17:08:37.547|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2020-06-18 17:08:37.547|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "[\r][\n]"
2020-06-18 17:08:37.734|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "HTTP/1.1 400 [\r][\n]"
2020-06-18 17:08:37.735|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Server: nginx[\r][\n]"
2020-06-18 17:08:37.735|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Date: Thu, 18 Jun 2020 09:08:36 GMT[\r][\n]"
2020-06-18 17:08:37.736|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Content-Type: application/json;charset=UTF-8[\r][\n]"
2020-06-18 17:08:37.736|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Transfer-Encoding: chunked[\r][\n]"
2020-06-18 17:08:37.736|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Connection: keep-alive[\r][\n]"
2020-06-18 17:08:37.737|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "X-Application-Context: cross-gateway:test:8080[\r][\n]"
2020-06-18 17:08:37.737|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "Set-Cookie: Track_id=rBCB8F7rLxRhG2WIFf7OAg==; expires=Fri, 18-Jun-21 09:08:36 GMT; domain=test.cn; path=/[\r][\n]"
2020-06-18 17:08:37.737|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "[\r][\n]"
2020-06-18 17:08:37.738|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "2b[\r][\n]"
2020-06-18 17:08:37.738|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "{"code":4004,"message":"parameter invalid"}[\r][\n]"
2020-06-18 17:08:37.738|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "0[\r][\n]"
2020-06-18 17:08:37.739|DEBUG|http-nio-8090-exec-2|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 << "[\r][\n]"

通過日誌可以看到請求失敗了,對方接口返回了參數無效

{"code":4004,"message":"parameter invalid"}

解決問題

在HTTP1.1中GET請求已經可以在body裏發送數據,但是既然用了RestTemplate,就要看一下RestTemplate是否提供了實現,這裏我們用的httpclient,默認用的HttpComponentsClientHttpRequestFactory工廠,查看了HttpComponentsClientHttpRequestFactory的createHttpUriRequest方法,發現GET請求是HttpGet,HttpGet繼承HttpRequestBase,HttpRequestBase是不支持傳遞body的。

protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
    switch (httpMethod) {
        case GET:
            return new HttpGet(uri);
        case HEAD:
            return new HttpHead(uri);
        case POST:
            return new HttpPost(uri);
        case PUT:
            return new HttpPut(uri);
        case PATCH:
            return new HttpPatch(uri);
        case DELETE:
            return new HttpDelete(uri);
        case OPTIONS:
            return new HttpOptions(uri);
        case TRACE:
            return new HttpTrace(uri);
        default:
            throw new IllegalArgumentException("Invalid HTTP method: " + httpMethod);
    }
}

查了資料發現HttpEntityEnclosingRequestBase是可以傳遞body的,那就自定義一個工廠繼承HttpComponentsClientHttpRequestFactory,重寫createHttpUriRequest方法,當發送的請求是GET請求時,創建自定義的繼承HttpEntityEnclosingRequestBase的類,這樣GET請求就可以傳送body。

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {

        return new HttpComponentsClientHttpRequestCRMFactory(httpClient);

    }

    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
        //設置整個連接池最大連接數 根據自己的場景決定
        connectionManager.setMaxTotal(200);
        //路由是對maxTotal的細分
        connectionManager.setDefaultMaxPerRoute(100);
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(10000) //服務器返回數據(response)的時間,超過該時間拋出read timeout
                .setConnectTimeout(5000)//連接上服務器(握手成功)的時間,超出該時間拋出connect timeout
                .setConnectionRequestTimeout(1000)//從連接池中獲取連接的超時時間,超過該時間未拿到可用連接,會拋出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
                .build();
        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .build();
    }

    private static final class HttpComponentsClientHttpRequestCRMFactory extends HttpComponentsClientHttpRequestFactory {
        public HttpComponentsClientHttpRequestCRMFactory(HttpClient httpClient) {
            super(httpClient);
        }

        @Override
        protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
            if (httpMethod == HttpMethod.GET) {
                return new HttpGetRequestForBody(uri);
            }
            return super.createHttpUriRequest(httpMethod, uri);
        }
    }

    private static final class HttpGetRequestForBody extends HttpEntityEnclosingRequestBase {
        public HttpGetRequestForBody(final URI uri) {
            super.setURI(uri);
        }

        @Override
        public String getMethod() {
            return HttpMethod.GET.name();
        }
    }
}

測試結果

再次測試結果,發現調用正確返回

2020-06-18 17:10:28.403|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "GET /cross/appms-internal/v1/portal/app/config/search HTTP/1.1[\r][\n]"
2020-06-18 17:10:28.404|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept: text/plain, application/json, application/*+json, */*[\r][\n]"
2020-06-18 17:10:28.404|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Content-Type: application/json;charset=UTF-8[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Content-Length: 59[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Host: dev-test.com[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Connection: Keep-Alive[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "User-Agent: Apache-HttpClient/4.5.10 (Java/1.8.0_201)[\r][\n]"
2020-06-18 17:10:28.407|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "Accept-Encoding: gzip,deflate[\r][\n]"
2020-06-18 17:10:28.408|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|73|http-outgoing-0 >> "[\r][\n]"
2020-06-18 17:10:28.408|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|87|http-outgoing-0 >> "{"devIdList":[164359,164893],"pageSize":10,"currentPage":1}"

和第一次的請求相比,這一次請求日誌中多了一句

2020-06-18 17:10:28.408|DEBUG|http-nio-8090-exec-1|org.apache.http.impl.conn.Wire|wire|87|http-outgoing-0 >> "{"devIdList":[164359,164893],"pageSize":10,"currentPage":1}"

如果還沒看出來,我在整理一下日誌

GET /cross/appms-internal/v1/portal/app/config/search HTTP/1.1[\r][\n]
Accept: text/plain, application/json, application/*+json, */*[\r][\n]
Content-Type: application/json;charset=UTF-8[\r][\n]
Accept-Charset: big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp[\r][\n]
Content-Length: 59[\r][\n]
Host: dev-test.com[\r][\n]
Connection: Keep-Alive[\r][\n]
User-Agent: Apache-HttpClient/4.5.10 (Java/1.8.0_201)[\r][\n]
Accept-Encoding: gzip,deflate[\r][\n]
[\r][\n]

{"devIdList":[164359,164893],"pageSize":10,"currentPage":1}

這個就是HTTP協議,可以看到最後一行就是body裏的數據,問題也解決了。

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