Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架。简单,却很强大!
jodd-http是一个轻巧的HTTP客户端。现在我们以一个简单的示例从源码层看看是如何实现的?
HttpRequest httpRequest = HttpRequest.get("http://jodd.org"); //1. 构建一个get请求 HttpResponse response = httpRequest.send(); //2.发送请求并接受响应信息 System.out.println(response);//3.打印响应信息
构建一个get请求
先复习一下http请求报文的格式:
下图展示一般请求所带有的属性
调用get方法构建http请求:
/** * Builds a GET request. */ public static HttpRequest get(String destination) { return new HttpRequest() .method("GET") .set(destination); }
method方法如下:
/** * Specifies request method. It will be converted into uppercase. */ public HttpRequest method(String method) { this.method = method.toUpperCase(); return this; }
set方法如下:
/** * Sets the destination (method, host, port... ) at once. */ public HttpRequest set(String destination) { destination = destination.trim(); // http method int ndx = destination.indexOf(' '); if (ndx != -1) { method = destination.substring(0, ndx).toUpperCase(); destination = destination.substring(ndx + 1); } // protocol ndx = destination.indexOf("://"); if (ndx != -1) { protocol = destination.substring(0, ndx); destination = destination.substring(ndx + 3); } // host ndx = destination.indexOf('/'); if (ndx == -1) { ndx = destination.length(); } if (ndx != 0) { host = destination.substring(0, ndx); destination = destination.substring(ndx); // port ndx = host.indexOf(':'); if (ndx == -1) { port = DEFAULT_PORT; } else { port = Integer.parseInt(host.substring(ndx + 1)); host = host.substring(0, ndx); } } // path + query path(destination); return this; }
上述方法,根据destination解析出一下几个部分:
1. 方法:HTTP1.1支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。
2. 协议:http或者https
3. 主机:请求的服务器地址
4. 端口:请求的服务器端口
5. 路径+查询参数,其中参数以“?”开头,使用“&”连接
/** * Sets request path. Query string is allowed. * Adds a slash if path doesn't start with one. * Query will be stripped out from the path. * Previous query is discarded. * @see #query() */ public HttpRequest path(String path) { // this must be the only place that sets the path if (path.startsWith(StringPool.SLASH) == false) { path = StringPool.SLASH + path; } int ndx = path.indexOf('?'); if (ndx != -1) { String queryString = path.substring(ndx + 1); path = path.substring(0, ndx); query = HttpUtil.parseQuery(queryString, true); } else { query = HttpValuesMap.ofObjects(); } this.path = path; return this; }
发送请求
先熟悉一下http响应报文的格式:
响应首部一般包含如下内容:
/** * {@link #open() Opens connection} if not already open, sends request, * reads response and closes the request. If keep-alive mode is enabled * connection will not be closed. */ public HttpResponse send() { if (httpConnection == null) { open(); } // prepare http connection if (timeout != -1) { httpConnection.setTimeout(timeout); } // sends data HttpResponse httpResponse; try { OutputStream outputStream = httpConnection.getOutputStream(); sendTo(outputStream); InputStream inputStream = httpConnection.getInputStream(); httpResponse = HttpResponse.readFrom(inputStream); httpResponse.assignHttpRequest(this); } catch (IOException ioex) { throw new HttpException(ioex); } boolean keepAlive = httpResponse.isConnectionPersistent(); if (keepAlive == false) { // closes connection if keep alive is false, or if counter reached 0 httpConnection.close(); httpConnection = null; } return httpResponse; }
1. 打开HttpConnection
/** * Opens a new {@link HttpConnection connection} using * {@link JoddHttp#httpConnectionProvider default connection provider}. */ public HttpRequest open() { return open(JoddHttp.httpConnectionProvider); } /** * Opens a new {@link jodd.http.HttpConnection connection} * using given {@link jodd.http.HttpConnectionProvider}. */ public HttpRequest open(HttpConnectionProvider httpConnectionProvider) { if (this.httpConnection != null) { throw new HttpException("Connection already opened"); } try { this.httpConnectionProvider = httpConnectionProvider; this.httpConnection = httpConnectionProvider.createHttpConnection(this); } catch (IOException ioex) { throw new HttpException(ioex); } return this; }
判断是否有连接,若没有连接则创建一个新的连接。
2. 创建连接实现
/** * Creates new connection from current {@link jodd.http.HttpRequest request}. * * @see #createSocket(String, int) */ public HttpConnection createHttpConnection(HttpRequest httpRequest) throws IOException { Socket socket; if (httpRequest.protocol().equalsIgnoreCase("https")) { SSLSocket sslSocket = createSSLSocket(httpRequest.host(), httpRequest.port()); sslSocket.startHandshake(); socket = sslSocket; } else { socket = createSocket(httpRequest.host(), httpRequest.port()); } return new SocketHttpConnection(socket); }
3. 创建socket
根据协议的不同,http使用SocketFactory创建socket,https使用SSLSocketFactory创建SSLSocket。最终使用SocketHttpConnection进行包装。
SocketHttpConnection继承自HttpConnection,实现了socket的输入输出流连接。注意:https创建完SSLSocket时需要进行握手。
public class SocketHttpConnection implements HttpConnection { protected final Socket socket; public SocketHttpConnection(Socket socket) { this.socket = socket; } public OutputStream getOutputStream() throws IOException { return socket.getOutputStream(); } public InputStream getInputStream() throws IOException { return socket.getInputStream(); } public void close() { try { socket.close(); } catch (IOException ignore) { } } public void setTimeout(int milliseconds) { try { socket.setSoTimeout(milliseconds); } catch (SocketException sex) { throw new HttpException(sex); } } /** * Returns <code>Socket</code> used by this connection. */ public Socket getSocket() { return socket; } }
打开Connection的输出流发送信息,打开connection的输入流接受返回信息。
OutputStream outputStream = httpConnection.getOutputStream();
sendTo(outputStream);
InputStream inputStream = httpConnection.getInputStream();
发送过程:
protected HttpProgressListener httpProgressListener; /** * Sends request or response to output stream. */ public void sendTo(OutputStream out) throws IOException { Buffer buffer = buffer(true); if (httpProgressListener == null) { buffer.writeTo(out); } else { buffer.writeTo(out, httpProgressListener); } out.flush(); }
将缓冲区的数据写入输出流,并发送。
接受数据并读取报文内容:
/** * Reads response input stream and returns {@link HttpResponse response}. * Supports both streamed and chunked response. */ public static HttpResponse readFrom(InputStream in) { InputStreamReader inputStreamReader; try { inputStreamReader = new InputStreamReader(in, StringPool.ISO_8859_1); } catch (UnsupportedEncodingException ignore) { return null; } BufferedReader reader = new BufferedReader(inputStreamReader); HttpResponse httpResponse = new HttpResponse(); // the first line String line; try { line = reader.readLine(); } catch (IOException ioex) { throw new HttpException(ioex); } if (line != null) { line = line.trim(); int ndx = line.indexOf(' '); httpResponse.httpVersion(line.substring(0, ndx)); int ndx2 = line.indexOf(' ', ndx + 1); if (ndx2 == -1) { ndx2 = line.length(); } httpResponse.statusCode(Integer.parseInt(line.substring(ndx, ndx2).trim())); httpResponse.statusPhrase(line.substring(ndx2).trim()); } httpResponse.readHeaders(reader); httpResponse.readBody(reader); return httpResponse; }
小结
从上面的代码,我们可以看出http使用socket来建立和destination的连接,然后通过连接的输出流和输入流来进行通信。
参考文献:
【1】http://www.it165.net/admin/html/201403/2541.html
【2】http://jodd.org/doc/http.html
http://www.cnblogs.com/davidwang456/p/4569283.html
相关推荐
赠送jar包:jodd-http-3.7.1.jar; 赠送原API文档:jodd-http-3.7.1-javadoc.jar; 赠送源代码:jodd-http-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-http-3.7.1.pom; 包含翻译后的API文档:jodd-...
赠送jar包:jodd-core-5.1.6.jar; 赠送原API文档:jodd-core-5.1.6-javadoc.jar; 赠送源代码:jodd-core-5.1.6-sources.jar; 赠送Maven依赖信息文件:jodd-core-5.1.6.pom; 包含翻译后的API文档:jodd-core-...
赠送jar包:jodd-bean-5.0.13.jar; 赠送原API文档:jodd-bean-5.0.13-javadoc.jar; 赠送源代码:jodd-bean-5.0.13-sources.jar; 赠送Maven依赖信息文件:jodd-bean-5.0.13.pom; 包含翻译后的API文档:jodd-bean-...
赠送jar包:jodd-core-3.7.1.jar; 赠送原API文档:jodd-core-3.7.1-javadoc.jar; 赠送源代码:jodd-core-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-core-3.7.1.pom; 包含翻译后的API文档:jodd-core-...
赠送jar包:jodd-upload-3.7.1.jar; 赠送原API文档:jodd-upload-3.7.1-javadoc.jar; 赠送源代码:jodd-upload-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-upload-3.7.1.pom; 包含翻译后的API文档:jodd-...
赠送jar包:jodd-http-3.7.1.jar; 赠送原API文档:jodd-http-3.7.1-javadoc.jar; 赠送源代码:jodd-http-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-http-3.7.1.pom; 包含翻译后的API文档:jodd-...
赠送jar包:jodd-bean-5.1.6.jar; 赠送原API文档:jodd-bean-5.1.6-javadoc.jar; 赠送源代码:jodd-bean-5.1.6-sources.jar; 赠送Maven依赖信息文件:jodd-bean-5.1.6.pom; 包含翻译后的API文档:jodd-bean-...
赠送jar包:jodd-core-3.7.1.jar; 赠送原API文档:jodd-core-3.7.1-javadoc.jar; 赠送源代码:jodd-core-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-core-3.7.1.pom; 包含翻译后的API文档:jodd-core-...
赠送jar包:jodd-upload-3.7.1.jar; 赠送原API文档:jodd-upload-3.7.1-javadoc.jar; 赠送源代码:jodd-upload-3.7.1-sources.jar; 赠送Maven依赖信息文件:jodd-upload-3.7.1.pom; 包含翻译后的API文档:jodd-...
java运行依赖jar包
赠送jar包:jodd-core-5.1.6.jar; 赠送原API文档:jodd-core-5.1.6-javadoc.jar; 赠送源代码:jodd-core-5.1.6-sources.jar; 赠送Maven依赖信息文件:jodd-core-5.1.6.pom; 包含翻译后的API文档:jodd-core-...
赠送jar包:jodd-bean-5.0.13.jar; 赠送原API文档:jodd-bean-5.0.13-javadoc.jar; 赠送源代码:jodd-bean-5.0.13-sources.jar; 赠送Maven依赖信息文件:jodd-bean-5.0.13.pom; 包含翻译后的API文档:jodd-bean-...
"jodd-joy-3.6.6.jar" 和 "jodd-joy-3.6.6-sources.jar" 代表了Jodd框架的“Joy”模块,可能包含了一些高级功能或特定领域的应用,同样提供了Base64工具的实现。 "jodd-swingspy-3.6.6.jar" 和 "jodd-swingspy-...
jodd-bean-3.7.1
赠送jar包:jodd-bean-5.1.6.jar; 赠送原API文档:jodd-bean-5.1.6-javadoc.jar; 赠送源代码:jodd-bean-5.1.6-sources.jar; 赠送Maven依赖信息文件:jodd-bean-5.1.6.pom; 包含翻译后的API文档:jodd-bean-...
java运行依赖jar包
jodd-bean-5.1.6.jar,jodd-bean-5.1.6-javadoc.jar,jodd-bean-5.1.6-sources.jar,jodd-core-5.1.6.jar,jodd-core-5.1.6-javadoc.jar,jodd-core-5.1.6-sources.jar,jodd-core-5.2.0.jar,jodd-http-5.2.0.jar,jodd-...
"jodd-all-3.1.0 Java 开发工具包"是一个综合性的软件包,专为Java开发者设计,提供了一系列的实用工具和库,旨在简化和加速开发过程。这个工具包的核心是Jodd框架,它包含了许多模块,覆盖了从HTTP服务器到数据处理...
"jodd-bean-3.4.5.zip"是一个开源项目的压缩包,它包含了Jodd Bean模块的3.4.5版本。Jodd是一个多用途的Java工具库,提供了多种功能,包括对象处理、HTTP客户端、数据库访问以及更多。在这个特定的版本中,我们主要...
Jodd是一个普通开源Java包。你可以把Jodd想象成Java的"瑞士军刀",不仅小,锋利而且包含许多便利的功能。 Jodd 提供的功能有: 1. 提供操作Java bean, 2. 可以从各种数据源加载Bean, 3. 简化JDBC的接连与代码, 4. ...