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 methodint 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 pathif (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 connectionif (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

转载于:https://www.cnblogs.com/davidwang456/p/4569283.html

简约之美Jodd-http--深入源码理解http协议相关推荐

  1. 简约官网引导页网站源码,站长必备

    简介: 简约官网引导页网站源码,站长必备 网盘下载地址: http://kekewl.cc/w59zRwLrZXS0 图片:

  2. 简约易收录的导航网站源码

    正文: 简约易收录的导航网站源码分享,之前用这个系统之前搜狗权重做到了4,至今还有人在卖这套程序. 安装说明 宝塔环境:Nginx -Tengine2.2.3 PHP5.6 + MySQL5.6.44 ...

  3. 轻量级简约的自动采集小说程序源码

    正文: 轻量级简约的自动采集小说程序源码,全程序自动采集​,更新提示:已经更新采集规则. 安装环境: 1.Nginx环境 2.php7.0,mysql 3.宝塔服务器 4.正常的域名 安装教程: 1. ...

  4. 苹果cms精仿某果Tv超美听书模板源码

    介绍: 苹果cms精仿芒果Tv超美听书模板源码 手机版修改logo,ting_wap/images/logo.png 电脑版修改logo,ting_pc/img/logo.png 编辑推荐 后台推荐5 ...

  5. 最新~博弈美业系统源码/美业门店管理系统源码/应用场景逻辑分析

    博弈美业系统源码/美业门店管理系统源码/应用场景逻辑分析 商家iPAD端 场景名称 场景流程举例 预约管理/美业系统源码 1.顾客团购了一个冻干粉, 打电话过来预约明天下午, 并指定要小王为她做护肤服 ...

  6. 福利吧简约朴素网站地址发布页源码

    介绍: 大方简约的地址发布页面HTML源码,可用于发布网站最新地址,留住用户必备方便找到回家的路,就单单一个html页面,需要的朋友下载吧! 网盘下载地址: https://zijiewangpan. ...

  7. 从hotspot底层对象结构理解锁膨胀升级过程||深入jdk源码理解longadder的分段cas优化机制——分段CAS优化

    深入jdk源码理解longadder的分段cas优化机制 longadder

  8. faster rcnn源码理解(二)之AnchorTargetLayer(网络中的rpn_data)

    转载自:faster rcnn源码理解(二)之AnchorTargetLayer(网络中的rpn_data) - 野孩子的专栏 - 博客频道 - CSDN.NET http://blog.csdn.n ...

  9. faster rcnn的源码理解(一)SmoothL1LossLayer论文与代码的结合理解

    转载自:faster rcnn的源码理解(一)SmoothL1LossLayer论文与代码的结合理解 - 野孩子的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/u ...

最新文章

  1. java web项目的目录结构以及各文件夹的功能是什么eclipse的web目录及各作用
  2. 成功解决Instructions for updating: Use `tf.global_variables_initializer` instead.
  3. float类型转integer_Java基础(一)之数据类型——全面,浅显易懂
  4. STL的deque容器
  5. Python存储和读取数据
  6. python怎样播放音乐_Python如何播放音乐?
  7. EXCEL工资条短信如何发送?
  8. 预测算法用java实现
  9. 机器视觉Halcon教程(1.介绍)
  10. 简单个人静态HTML网页设计作品 DIV布局个人介绍网页模板代码 DW个人网站制作成品 web网页制作与实现
  11. 2022 Google 谷歌开发者大会亮点抢先看
  12. 合唱队形(线性DP)
  13. Markdown语句总结
  14. 豆瓣高分JAVA书籍,值得收藏
  15. 【Android】JNI调用(完整版)
  16. 如何选择智能车牌识别摄像机
  17. dblink 怎么用
  18. OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel
  19. 上古卷轴5mo未安装python_勇敢的罗宾爵士 - Monty Python Mod
  20. 普通大学生自学 JAVA 怎样才能进BAT大厂?

热门文章

  1. c#客户端 通过用户名密码访问服务器文件,C#如何连接服务器共享文件夹
  2. python判断能否组成三角形_牛鹭学院:学员笔记|Python: 输入三条边,判断是否可以成为三角形...
  3. pandas把多个列相加求和、输出字母a-z
  4. DynamicArray
  5. javafx sdk html 布局,JavaFX2开发教程
  6. java request 原理_JavaWeb-seession原理
  7. java osgi web开发_基于 OSGi 和 Spring 开发 Web 应用
  8. 正版七日杀服务器存档,七日杀网吧怎么存档 七日杀网吧存档读档方法介绍-游侠网...
  9. opencv 霍夫曼变换 直线提取
  10. Leetcode 122.买卖股票的最佳时机 II (每日一题 20210618)