现在,我们已经充分了解了 HTTP 和 Socket 的关系,也了解了 HTTP 报文的格式,为了让小伙伴能够加深对这两个概念的理解,本文我们来看看如何利用 Socket 模拟 HTTP 请求。如果小伙伴们对 HTTP 和 Socket 的关系、HTTP 报文格式尚不熟悉的话,可以参考前面的文章 Http 和 Socket 到底是哪门子亲戚?。
由于 HTTP 是基于 TCP 协议的应用层协议,因此我们可以用更为底层的方式来访问 HTTP 服务,即直接使用 Socket 完成 HTTP 的请求和响应。我们前面说过,HTTP 的任务就是完成数据的包装, Socket 提供了网络的传输能力,所以我们只需要按照 HTTP 报文的格式来组装数据,然后利用 Socket 将数据发送出去,就能得到回应。
POST 请求上传数据
假设我现在有一个数据接口 http://localhost/hello
,该接口每次接收一个参数 name ,调用成功之后返回给用户一个 hello:name
字符串,那我们用 Socket 来实现这样一个 HTTP 请求。
首先,我们要先组装出 HTTP 的请求头,如下(如果小伙伴对下面这个请求头有疑问,请复习 Http 和 Socket 到底是哪门子亲戚?一文):
1 |
|
我这里为了简单,只添加了三个请求头,然后我们通过 Socket 将上面这个字符串发送出去:
1 |
|
我在 Serlvet 中接收这个请求并作简单处理,如下:
1 |
|
然后通过 Socket 中的输入流我就能拿到响应结果,如下:
1 |
|
响应结果如下:
1 |
|
这是一个简单的通过 POST 请求下载文本的案例。接下来我们再来一个 GET 请求下载图片的案例,来加深对 Socket 的理解。
GET 请求下载图片
这个实际上也不难,但是要实现图片的下载需要我们首先熟悉HTTP响应的数据格式,不熟悉的小伙伴可以阅读 Http 和 Socket 到底是哪门子亲戚?一文。
下载图片,响应头是文本文件,响应数据是二进制文件,我们要想办法通过空行将这两块数据分开,分别处理。为了解决这个问题,我首先提供一个工具类,这个工具类用来实现一行一行的解析字节流,如下:
1 |
|
然后将响应中的头信息和图片分别保存在不同的文件中,数据解析的核心思路就是一行一行读取响应数据,当遇到 \r\n
表示头信息已经读取完了,要开始读取二进制数据了,二进制数据读取到之后,将之保存成图片即可。核心代码如下:
1 |
|
OK,Socket 模拟 HTTP 请求我们就先说到这里,两个案例,希望能够加深小伙伴对 Socket 和 HTTP 的理解。