不過在我們的環境中,遇到了一點奇妙的需求,Apache 的套件有點不合用
剛好又發現有網友提到,Jersey 本身就有提供 Jersey client 可以作為送出 HTTP 的方法
而且我們本來就用 Jersey 來提供 RESTful 介面,不需要另外引用函式庫,所以就拿來試試看了。
因為我們的環境中,是先從 RESTful 介面收到瀏覽器送來的要求後,轉送一份給另一台主機
所以下述的範例程式碼中,流程會以 RESTful 介面作為起點。
RESTful 介面的程式碼如下:
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Provider @Path("") public class Wrapper { private static Logger log = LoggerFactory.getLogger("Wrapper"); private @Context HttpHeaders headers; private @Context UriInfo uriInfo; @GET @Produces(MediaType.APPLICATION_JSON) public Response getStatus() { log.debug("URI: " + uriInfo.getRequestUri().getQuery()); return DefaultHttpProxy.get(headers, uriInfo); } }
簡單來說,就是收到一個 HTTP 要求時,就把這個要求中夾帶的標頭和 URL 參數丟給 DefaultHttpProxy 這個類別。
而 DefaultHttpProxy 的程式碼如下:
import java.io.InputStream; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.glassfish.jersey.filter.LoggingFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A default implementation for replaying the HTTP request to another RESTful service. * @author Wayne Yeh @ 2015-10-14 */ public class DefaultHttpProxy { private static Logger log = LoggerFactory.getLogger("DefaultHttpProxy"); /** * Send GET request with specified headers and query parameters. * @param headers Request headers. * @param uriInfo Request URI. * @return Response from the target of proxy. */ public static Response get (HttpHeaders headers, UriInfo uriInfo) { Builder httpBuilder = buildBaseRequest(headers, uriInfo); return httpBuilder.get(); } private static Builder buildBaseRequest (HttpHeaders headers, UriInfo uriInfo) throws IllegalArgumentException { if(uriInfo == null) throw new IllegalArgumentException("No target URI is specified."); // ----------------------------------------------------------------------------------------- // // Initiate a HTTP request for replay the client's request to Elasticsearch. // // ----------------------------------------------------------------------------------------- // // Initiate the request builder. Client httpClient = ClientBuilder.newClient(); Builder httpBuilder = httpClient.target("http://localhost:9200/" + subUri).register(new LoggingFilter()).request(); log.debug("Try to request {}", "http://localhost:9200/" + subUri); // Try to replay the headers to the request builder. if(headers != null) { // List the headers and replay them to the request builder. Iterator<Entry<String, List<String>>> headersIter = headers.getRequestHeaders().entrySet().iterator(); while (headersIter.hasNext()) { Entry<String, List<String>> header = headersIter.next(); // Extract each of the headers and put it to the request builder. for(String value : header.getValue()) { log.debug("Extract request header {} : {}", header.getKey(), value); httpBuilder.header(header.getKey(), value); } } } // Set that the API accept JSON. httpBuilder.accept(MediaType.APPLICATION_JSON_TYPE); return httpBuilder; } }
其中真正在進行發送 HTTP 要求的是 46~67 行以及 34 行,流程大概是先建立一個新的 Client 實例
然後透過 target() 方法指定要發送的目標 URI
後面接的 register() 是要註冊一個 debug 用的 Filter,可以讓 Jersey client 在運作時印出 log
然後呼叫 request() 可以獲得一個 Builder 類別的實例,能夠做後續的 HTTP 要求的細部設定。
如果有需要指定標頭等資訊的話,可以透過 Builder.header() 方法來設定(51~64 行)
最後要送出要求時,因為這裡是用 GET 送出,因此就呼叫 Builder.get() 就可以送出去了(34 行)。
回應的會是 Jersey 一貫的 Response 物件~
在我們的案例中,本來也要包 Response 物件作為回給客戶端(瀏覽器)的回應
因此 Jersey client 幫我包好了也省了一番轉換的功夫!XD
在執行時,瀏覽器輸入 http://localhost:8080/?a=a
得到的 log 如下:
2015-10-14 14:56:28.888 | DEBUG | RequestFilter | Get request URI from http://localhost:8080/?a=a 2015-10-14 14:56:28.891 | DEBUG | ElasticsearchWrapper | Get is called. 2015-10-14 14:56:28.891 | DEBUG | ElasticsearchWrapper | URI: a=a 2015-10-14 14:56:29.001 | DEBUG | DefaultHttpProxy | Try to request http://localhost:9200/?a=a 2015-10-14 14:56:29.006 | DEBUG | DefaultHttpProxy | Extract request header User-Agent : Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0 2015-10-14 14:56:29.006 | DEBUG | DefaultHttpProxy | Extract request header Connection : keep-alive 2015-10-14 14:56:29.006 | DEBUG | DefaultHttpProxy | Extract request header Host : localhost:8080 2015-10-14 14:56:29.007 | DEBUG | DefaultHttpProxy | Extract request header Accept-Language : zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 2015-10-14 14:56:29.007 | DEBUG | DefaultHttpProxy | Extract request header Accept-Encoding : gzip, deflate 2015-10-14 14:56:29.007 | DEBUG | DefaultHttpProxy | Extract request header Accept : text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Oct 14, 2015 2:56:29 PM org.glassfish.jersey.filter.LoggingFilter log INFO: 1 * Sending client request on thread qtp2110121908-17 1 > GET http://localhost:9200/?a=a 1 > Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json 1 > Accept-Encoding: gzip, deflate 1 > Accept-Language: zh-TW,zh;q=0.8,en-US;q=0.5,en;q=0.3 1 > Connection: keep-alive 1 > Host: localhost:8080 1 > User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0 Oct 14, 2015 2:56:29 PM org.glassfish.jersey.client.internal.HttpUrlConnector setOutboundHeaders WARNING: Attempt to send restricted header(s) while the [sun.net.http.allowRestrictedHeaders] system property not set. Header(s) will possibly be ignored. Oct 14, 2015 2:56:29 PM org.glassfish.jersey.filter.LoggingFilter log INFO: 1 * Client response received on thread qtp2110121908-17 1 < 200 1 < Content-Length: 339 1 < Content-Type: application/json; charset=UTF-8
參考資料:
沒有留言:
張貼留言