簡約之美Jodd-http--應用一籮筐


Jodd-http是一個微型的、簡約的http client,然而簡單而且方便。使用它可以輕松的實現發送請求和讀取響應。它的目標就是日常應用變的非常簡單,從而簡化開發人員的工作。

了解Jodd-http的最好方法就是示例程序。

簡單的GET方法

    HttpRequest httpRequest = HttpRequest.get("http://jodd.org");
    HttpResponse response = httpRequest.send();

    System.out.println(response);

上述代碼實現了一個get請求,並打印出響應結果。

我們看一下響應結果:

HTTP/1.1 200 OK
Date: Fri, 12 Jun 2015 02:43:50 GMT
Server: Apache
Last-Modified: Mon, 25 May 2015 21:44:44 GMT
Accept-Ranges: bytes
Content-Length: 14056
Cache-Control: max-age=0, public
Expires: Fri, 12 Jun 2015 02:43:50 GMT
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<html>
<head>
..................................
...................................
</body>
</html>

請結合下圖理解

wKiom1MpmHWALc2UAADu14JLceA655.jpg

你也可以這么寫:

    HttpResponse response = HttpRequest.get("http://jodd.org").send();

    System.out.println(response);

或者一步步構建:

    HttpRequest request = new HttpRequest();
    request
        .method("GET")
        .protocol("http")
        .host("srv")
        .port(8080)
        .path("/api/jsonws/user/get-user-by-id");

好吧,了解一下請求的樣式吧:

wKioL1MpX-qwK1-PAAExXPRpR8M814.jpg

讀取響應報文

   發送消息后,響應報文存放在HttpResponse實例中,可以調用HttpResponse的方法獲取statusCode、statusPhrase或者報文頭屬性。

  讀取報文本身的方法主要有三種:

  body()--通常是ISO-8859-1編碼格式的基本報文內容。

  bodyText()--根據報文頭"Content-Type"屬性值的編碼格式編譯的報文。

  BodyByte()--以字節數組形式返回的基本報文,例如下載一個要保存的文件。

注意:在使用bodyText()方法前,必須使用charset()方法指定編碼格式。

查詢參數

在get方法中,查詢參數可以在url中指定(需要正確的編碼),如:

    HttpResponse response = HttpRequest
        .get("http://srv:8080/api/jsonws/user/get-user-by-id?userId=10194")
        .send();

或者通過query()方法設置,如:

    HttpResponse response = HttpRequest
        .get("http://srv:8080/api/jsonws/user/get-user-by-id")
        .query("userId", "10194")
        .send();

設置一個參數可以使用query()方法,或者每個參數調用一次query()方法。

當然也可以使用Map<String,String>做為一個參數進行傳參。

注意:查詢參數(報文頭或者表單參數)可以重復的。內部它們存儲在數組中。使用removeQuery方法來刪除參數或者多次調用query方法來替換參數。

query還可以讀取所有內部參數:

    Map<String, Object[]> httpParams = request.query();
    httpParams.put("userId", new String[] {"10194"});

基本認證

基本認證非常簡單:

request.basicAuthentication("test", "test");

post方法和表單參數

和get方法中的query類似:

    HttpResponse response = HttpRequest
        .post("http://srv:8080/api/jsonws/user/get-user-by-id")
        .form("userId", "10194")
        .send();

可以看出,在post方法中使用form來指定表單參數。form使用方法和query的使用方法完全相同。

上傳文件

同樣,也非常容易,只需要將文件增加到form參數中。示例如下:

    HttpRequest httpRequest = HttpRequest
        .post("http://srv:8080/api/jsonws/dlapp/add-file-entry")
        .form(
            "repositoryId", "10178",
            "folderId", "11219",
            "sourceFileName", "a.zip",
            "mimeType", "application/zip",
            "title", "test",
            "description", "Upload test",
            "changeLog", "testing...",
            "file", new File("d:\\a.jpg.zip")
        );

    HttpResponse httpResponse = httpRequest.send();

上面就是全部代碼了。

監控文件上傳進度

  上傳大文件時,需要監控上傳進度。HttpProgressListener提供了這種功能:

    HttpResponse response = HttpRequest
        .post("http://localhost:8081/hello")
        .form("file", file)
        .monitor(new HttpProgressListener() {
            @Override
            public void transferred(long len) {
                System.out.println(len/size);
            }
        })
        .send();

  在文件上傳前,HttpProgressListener計算出callbackSize---每次要傳輸的文件塊的字節數。默認情況下為整個文件的1%大小。一般情況下,不會少於512字節。

  HttpProgressListener包含了一個內部成員size,代表了整個請求的大小。注意:整個請求的size不僅僅是文件,它是整個要發送的請求的真實字節數,通常比大文件的size要大一些(參見請求報文格式)。

報文頭

增加或者獲取報文頭參數,可以使用header()方法。一些通用的報文頭參數已經定義好了,因此你可以通過contentType()等類似方法來查詢。

壓縮、解壓報文

使用unzip()解壓報文示例

    HttpResponse response = HttpRequest
        .get("http://www.liferay.com")
        .acceptEncoding("gzip")
        .send();

    System.out.println(response.unzip());

使用body方法

可以手動設置請求報文的內容--有時,一些api允許在body內指明類似的命令:

    HttpResponse response = HttpRequest
        .get("http://srv:8080/api/jsonws/invoke")
        .body("{'$user[userId, screenName] = /user/get-user-by-id' : {'userId':'10194'}}")
        .basicAuthentication("test", "test")
        .send();

設置body后可以摒棄上面form()方法來設置參數。

然而,在HttpResponse中使用body()方法去接收報文內容,這樣更有意義。

字符和編碼格式

  默認情況下,query和form參數使用utf-8編碼。全局上可以通過JoddHttp來重新設置,或者局部如下所示:

    HttpResponse response = HttpRequest
        .get("http://server/index.html")
        .queryEncoding("CP1251")
        .query("param", "value")
        .send();

當然,可以使用類似的方式設置form的編碼格式。進而,表單提交時檢測報文頭"Content-type"中的值,若存在,將使用該值。接收報文時,body()方法通常返回ISO-8859-1編碼格式的報文,若要返回指定的格式,可以使用bodyText()方法,此時需要預先設置編碼格式"Content-type"的值。

HttpConnection

  HttpConnection是封裝了http物理通信的接口,調用send()方法時,http將open()一個連接(不存在該連接時)。內部里,HttpConnectionProvier創建該連接。參見上篇文章(簡約之美Jodd-http--深入源碼理解http協議).默認的連接提供者是基於socket的,它通常返回一個新創建的SocketHttpConnection實例,該實例簡單包裝了一個打開的socket。也可以使用自定義的HttpConnectionProvider,例如你可以擴展SocketHttpConnectionProvider,重寫createSocket()方法,讓其從socket池中返回socket或者返回不同過期時間的socket。

Socket

  如上所述,http通信通過普通的socket來完成。因此在發送數據前可以改變socket的行為,下面示例展示了http如何改變socket行為。

SocketHttpConnection

  通過httpConnection調用socket:

    HttpRequest request = HttpRequest.get()...;
    request.open();
    SocketHttpConnection httpConnection =
        (SocketHttpConnection) request.httpConnection();
    Socket socket = httpConnection.getSocket();
    socket.setSoTimeout(1000);
    ...
    HttpResponse response = request.send();

SocketHttpConnectionProvider

  另外一種方法是SocketHttpConnectionProvider,創建自己的provider:

    public class MyConnectionProvider extends SocketHttpConnectionProvider {
        protected Socket createSocket(
                SocketFactory socketFactory, String host, int port)
                throws IOException {
            Socket socket = super.createSocket(socketFactory, host, port);
            socket.setSoTimeout(1000);
            return socket;
        }
    }

然后使用open方法獲取socket

    HttpConnectionProvider connectionProvider = new MyConnectionProvider();
    ...
    HttpRequest request = HttpRequest.get()...;
    HttpResponse response = request.open(connectionProvider).send();

若要設置自定義的connectionProvider的默認ConnectionProvider而適用於所有的通信,只需要將它賦給JoddHttp.httpConnectionProvider就不必顯式調用open()方法。

持久連接(keep-alive)

  默認情況下,所有的連接時關閉的。http允許通設置連接為keep-alive模式從而使連接一直存在。在keep-alive模式下,在通信會話中,第一次請求時打開一個HttpConnection,以后重用該連接;若非必要,socket不會再次打開,因而可以被多個request重復使用。

File:HTTP persistent connection.svg

  有許多方法可以做到,但最簡單的方法如下所示:

        HttpRequest request = HttpRequest.get("http://jodd.org");
        HttpResponse response = request.connectionKeepAlive(true).send();

        // next request
        request = HttpRequest.get("http://jodd.org/jodd.css");
        response = request.keepAlive(response, true).send();

        ...

        // last request
        request = HttpRequest.get("http://jodd.org/jodd.png");
        response = request.keepAlive(response, false).send();

        // optionally
        //response.close();

代理

  HttpConnectionProvider支持代理,只需要提供指明代理信息(類型、地址、端口、用戶名、密碼)的ProxyInfo實例即可。支持HTTP/SOCKS4/SOCKET5三種類型,其區別是:

SOCKS:防火牆安全會話轉換協議 (Socks:Protocol for sessions traversal across firewall securely) Socks 協議提供一個框架,在 TCP 和 UDP 域中的客戶機/服務器應用程序能更方便安全地使用網絡防火牆所提供的服務。這個協議從概念上來講是介於應用層和傳輸層之間的 “中介層(shim-layer)”,所以不提供傳遞 ICMP 信息之類的網絡層網關服務。
Socks4和Socks5都屬於Socks協議,只是由於所支持的具體應用不同而存在差異。
Socks4代理只支持TCP應用,而Socks5代理則可以支持TCP和UDP兩種應用。不過由於Socks5代理還支持各種身份驗證機制,服務器端域名解析等;而Socks4代理沒有,所以通常對外開放的 Socks代理都是Socks4代理。因此,UDP應用通常都不能被支持。也就是說,Socks4能做的Socks5都可以做,而socks5能做的,Socks4不一定都可以做。

 輸入流解析

   HttpRequest和HttpResponse都實現了讀取輸入流的方法readFrom(InputStream)。下面舉例說明服務器如何讀取請求。

HttpBrowser

   當需要通過改變目標地址來模擬一下"移動"的場景時,僅僅發送請求、接收響應是不夠。例如登陸需要在當前session內讀取不同目標地址的內容。

  HttpBrowser能完成這種功能。它發送請求,自動處理301和302跳轉,從響應報文中讀取cookies存到新的請求報文中等等。簡單示例如下:

    HttpBrowser browser = new HttpBrowser();

    HttpRequest request = HttpRequest.get("www.facebook.com");
    browser.sendRequest(request);

    // request is sent and response is received

    // process the page:
    String page = browser.getPage();

    // create new request
    HttpRequest newRequest = HttpRequest.post(formAction);

    browser.sendRequest(newRequest);

HttpTunnel

   jodd-http提供了一個靈活的構建http隧道的方法(簡單代理和目的地址的隧道),HttpTunnel實現了此功能。

參考文獻:

【1】 http://jodd.org/doc/http.html

【2】http://www.it165.net/admin/html/201403/2541.html

【3】http://www.cnblogs.com/skynet/archive/2010/12/11/1903347.html

【4】http://www.ccproxy.com/socks4-yu-socks5-de-qu-bie-jie-shao.htm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM