RestTemplate 使用總結

場景:

認證服務器須要有個 http client 把前端發來的請求轉發到 backend service, 而後把 backend service 的結果再返回給前端,服務器自己只作認證功能。前端

遇到的問題:

  • 長鏈接以保證高性能。RestTemplate 自己也是一個 wrapper 其底層默認是 SimpleClientHttpRequestFactory ,若是要保證長鏈接, HttpComponentsClientHttpRequestFactory 是個更好的選擇,它不只能夠控制可以創建的鏈接數還能細粒度的控制到某個 server 的鏈接數,很是方便。在默認狀況下,RestTemplate 到某個 server 的最大鏈接數只有 2, 通常須要調的更高些,最好等於 server 的 CPU 個數json

  • access_token 不該傳到 backend service. backend service 之間通訊不須要 token,由於到這些服務的請求都是已經認證過的,是可信賴的用戶發出的請求。所以轉發請求時要把 parameter 從 request url 中刪掉。刪除 parameter 說難不難,說簡單其實還有點麻煩,網上有一個 UrlEncodedQueryString 能夠參考下,它封裝了不少函數,其中就包括從url 中摘掉指定 header服務器

  • 請求的 HttpMethod 問題。 HttpMethod 有不少種,http client 不該該對每種 Http method 都單獨處理,因此應選用 RestTemplate 的 exchange 方法。exchange 方法要求給出 RequestBody 參數,而對於 Get 請求,這部分每每爲空,因此咱們要在 controller 中聲明 @RequestBody(required = false) String bodyapp

  • exchange 的返回值和 controller 的返回值。Restful API 通常都是返回 json 的,因此最簡單的是 exchange 和 controller 直接返回 String,可是返回 String 會有不少問題: 首先是若是某些 API 返回的是圖片,那麼這個 client 就傻掉了,須要爲圖片接口專門寫 API,此外若是 backend service 返回的是 Gzip,那麼此 client 必須對 gzip 先解壓縮再返回請求者,若是不解壓縮的話,至關於對着 gzip 數據作了到 String 類型的強制轉換,使得請求者拿到的數據沒法解析,因此最好的返回值是 byte[]。對於那種比較大的 json 返回值,省去了對 String 的類型轉換後還能帶來很大的性能提高異步

  • 關於返回值是 byte[] 仍是 ResponseEntity<byte[]> 的問題。我以爲仍是 ResponseEntity<byte[]> 好些,由於它就是 backend service 的結果。若是返回 byte[] 的話,還要對 HttpServletResponse 的 Header 進行修改,設置 Content-type, Content-encoding 等等。async

下面是個人用法

@PostConstruct
    public void setProperties() {
        clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
                HttpClientBuilder.create()
                        .disableContentCompression()
                        .setMaxConnPerRoute(restTemplateConfig.getMaxConnPerRoute())
                        .setMaxConnTotal(restTemplateConfig.getMaxConn()).build());
        restTemplate = new RestTemplate(clientHttpRequestFactory);
    }


    public RestTemplate getInstance() {
        return new RestTemplate(new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build()));
    }

    public ResponseEntity<byte[]> mirrorRest(@RequestBody(required = false) String body, HttpMethod method,
                          HttpServletRequest request, HttpServletResponse response, URI uri) throws URISyntaxException {

        HttpEntity entities = new HttpEntity(body, extractHeaders(request));

        //delete accesstoken before mirror to backend server
        UrlEncodedQueryString queryString = UrlEncodedQueryString.parse(uri);
        queryString.remove("access_token");
        uri = queryString.apply(uri);

        ResponseEntity<byte[]> responseEntity = restTemplate.exchange(uri, method, entities, byte[].class);

        return responseEntity;
    }

須要改進的地方

  • HttpComponentsClientHttpRequestFactory 的配置粒度不夠細,能夠配合 RequestConfig 肯定某一個 service 須要多少鏈接數。函數

  • RestTemplate 有異步版本 asyncRestTemplate, 能夠考慮用它結合 netty 進一步提高程序性能,可是目前來說已經夠好了性能

相關文章
相關標籤/搜索