不過在我們的環境中,遇到了一點奇妙的需求,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
參考資料:
沒有留言:
張貼留言