認證服務器須要有個 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 進一步提高程序性能,可是目前來說已經夠好了性能