Jodd之HTTP

Jodd提供一个很轻量级、原生的的http客户端,使用起来很简单、方便。它能很方便的发送和接收http消息。

Http Get方法

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

System.out.println(response);

jodd http中所有的类都支持连续调用,因此上面的代码也可以写成:

HttpResponse response = HttpRequest.get("http://jodd.org").send();
<!--more-->

System.out.println(response);

当然也可以一步步的创建http请求:

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

接收http消息

HTTP消息发送之后,服务器返回的消息都会存储在HttpResponse实例中。我们可以从HttpResponse实例中提取出各种属性,如statusCode()或者statusPhrase(),或者其他的头消息等。 当然最重要的是从HttpResponse中读取http body。可以使用如下几种方法:

  • body() - 原生的body内容,经常是以ISO-8859-1编码的
  • bodyText() - body文本,以http头"Content-Type"指明的方式编码
  • bodyBytes() - 原生的字节流,所以可以用来下载文件

bodyText()会使用"Content-Type"指明的方式进行解码。如果http response没有指定编码格式,那就要在调用bodyText()之前,手动调用charset()方法指定编码。

url参数

对于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()方法,也可以直接传递一个`Map过去。 要注意的是: url参数(包括头消息参数和form表单参数)都可以重复。调用removeQuery可以移除参数。
最后,可以通过通过query方法一次性获取所有参数.

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

HTTP基本认证

http基本认证可以很简单的用下面的方法实现:

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

POST方法和表单参数

和GET方法类似:

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

文件上传

同样的,在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(需要上传字节流大小,单位是byte)。默认返回总大小的1%(如果总大小小于512字节,按512字节处理)。 HttpProgressListener内含了变脸size,来表示请求的大小。需要注意的是,这里计算的是整个http请求的大小,而不仅仅是文件的。所以计算出来的值,会比文件大一些。

HTTP消息头

可以通过header()方法来get或者set消息头,一些常用的消息头已经定义成方法了,比如contentType()

GZIP内容

如果http返回的是gzip压缩的内容,可以使用下面的方法解压缩:

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

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

使用body方法

也可以使用body()方法来手动设置http 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()方法,jodd会丢弃之前使用form方法设置的参数.

编码

默认情况下,jodd的http参数以UTF-8编码。我们可以在全局变量JoddHttp中修改,也可以在具体实例中修改:

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

也可以使用类似的方法,设置form表单的编码。但是如果在http消息头Content-Type中定义了编码,jodd会优先使用Content-type中的编码。 当收到http响应时,body()方法用来获取原生的string(ISO-8859-1编码格式)。bodyText()会使用Content-type中定义的编码格式,来获取响应的内容。

HTTP连接

在jodd-http中,http底层的通信都是由HttpConnection来完成的。调用send()方法时,如果连接没有打开,HTTP会调用open()方法打开连接。连接是通过HttpConntionProvider对象创建的。默认情况下,HttpConnectionProvider是基于socket的,并且每次调用都会返回一个新的SocketHttpConntion实例。 很多时候,我们可能需要自定义HttpConnectionProvider。例如,我们可以继承SockerHttpConnectionProvider类,并且overridecreateSocket()方法从socket连接池中返回socket连接,或者为socket设置不同的超时时间。 或者,我们也可以直接返回HttpConnection,不使用provider。

Socket

如上所述,http通信都依赖Socket.我们可能经常需要对Socket进行一些调整,下面提供两种方法:

SocketHttpConnection

我们知道http消息是由HttpConntionProvideropen连接,然后send出去的。我们可以在open连接之后,获取到HttpConntion对象,并且把它强转成SocketHttpConnection对象。

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

SocketHttpConnectionProvider

另一种方法是自定义HttpConnectionProvider,我们需要继承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()方法中直接使用这个provider:

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

也可以把自定义的provider设置成jodd-http默认的provider,这样就可以全局使用了,不用每次调用open()方法时手动指定,方法是:

    JoddHttp.httpConnectionProvider = new MyConnectionProvider();

Keep-Alive

默认,所有的连接都会被附带上closed的标记,来减少服务器的开销。在HTTP中允许使用keep-alive来保持长连接。在第一次发送请求的时候,HttpConnection被创建,在之后的会话中都会重复使用;除非必要,否则不会创建新的socket连接,因此一个socket连接,会被多个请求使用。 保持keep-alive有几种方式,下面是最近简单的一种:

    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();

上面的例子里,使用一个HttpConnection对象发送了几条http请求(也就是一个socket连接)。keep-alive模式下,HTTP会重复使用已经建立的连接,持续监听服务器的响应。如果服务器发送close指令,这条连接就会被关闭,然后jodd会再创建一条新的连接,以便发送后续的请求,所以对我们来说,持续调用keepAlive()方法就好,jodd会在后台自动完成这一切。在接收完之后一个请求后,不要忘记传入一个false参数过去,来告诉服务器,可以关闭这条连接了。(如果在服务器响应有异常,我们可以调用response.close()方法主动断开连接)还有一点,在keep-alive模式下,如果连接必须被断开(如keep-alive次数到达上限或者服务器超时),在初始化新的连接时,会使用之前的connection provider.

Http代理

HttpConnectionProvider允许我们指定代理服务器。我们需要创建一个ProxyInfo对象传进去(需要指定类型、地址、端口、username、password)。 HTTP支持http代理,SOCKS4代理和SOCK5代理。

从InputStreams中解析数据

无论是HttpRequest还是HttpResponse都有readFrom(InputStream)的方法。简单来说,我们可以使用这个方法来解析输入流。在服务端,我们可以只用这个方法来获取用户的输入。

HttpBrowser

仅仅发送简单的请求,和读取服务器响应并不能满足我们的需求,有时候请求时相互影响、连续的。比如,有时候我们需要在浏览器上执行登录,然后在才能继续浏览,浏览器会维持我们的会话信息(session)。 HttpBroser提供类似的功能。它能发送http消息,自动处理301, 302跳转,从响应消息中读取cookie信息,然后保存下来,再后续的请求中自动使用。下面是一个例子:

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);

Browser对象会自动处理所有的cookie,也支持keep-alive连接。

HttpTunnel

HTTP is so flexible that you can easily build a HTTP tunnel with it - small proxy between you and destination. We even give you a base class: HttpTunnel class, that provides easy HTTP tunneling. It opens server socket on one port and tunnels the whole HTTP traffic to some target address. TinyTunnel is one implementation that simply prints out the whole communication to the console.

版权声明

本站文章、图片、视频等(除转载外),均采用知识共享署名 4.0 国际许可协议(CC BY-NC-SA 4.0),转载请注明出处、非商业性使用、并且以相同协议共享。

© 空空博客,本文链接:https://www.yeetrack.com/?p=1232