http杂谈
因为笔者经常和协议打交道,所以这个专题就从协议入手谈一下我对协议的认识。废话不多说进入正题。
之所以写http的协议是因为现在web开发多如猪毛,算是自己一点体会,错误的地方请大家斧正。本文根据rfc2616 http1.1撰写。
http是Hypertext Transfer Protocol的缩写,超文本传输协议。基于OSI模型第四层的tcp,属于OSI模型的第七层,同层的还有telnet ,ftp等。下面是一个http请求的例子,以此展开。
http http如上图所示,既然说http是文本协议,就是说是可见字符传输,不像coap,mqtt等二进制协议包含不可见字符。当然有的同学就会说了,那我不可见字符就不能传输了?废话,当然可以,要不然要payload干吗?没说payload里面不能有不可见字符啊。言归正传,下面是对上面图片的解析。
nc -l 8000
笔者本机监听8000端口,其实就相当于一个监听8000端口tcp服务端,如果你要接受udp包加个-u参数。这里说的http协议建立在tcp连接之上大家应该能理解了。也就是说在tcp三次握手建立连接之后才开始传输http报文。
请求
POST /test HTTP/1.1
此部分包括请求方法、请求地址和协议版本,POST 表明http请求的方法,GET,POST,PUT,DELETE等,然后紧接着是一个空格,加上你要访问的资源路径加空格,再加上你采用的协议版本,这里笔者使用的是http 1.1,然后换行符,下面是http请求头部
Host: 127.0.0.1:8000
Host表明你要访问的主机+端口,这里有人会有疑问,我tcp里面连接里面已经有ip和端口了,你这里为什么还要有主机和端口,原因是由于同一个机器上面可能部署多个服务通过解析域名+端口指定服务,同时也可以用作服务端校验客户端的一种手段。在rfc1945 1.0的定义中不带host头,1.1中必须要携带host,不然会报400 bad request(也就是不是正确的http请求)
User-Agent: PostmanRuntime/7.1.1
User-Agent 客户端标识,告诉服务端这个请求是啥client发起的,要是你要限制客户端也可以在这里做文章。
Accept: */*
client想要接受的数据类型,可以是多个,大家看到*理论上应该能想到这是所有的意思啦。
Accept-Encoding: gzip, deflate
client告诉服务端,我支持gzip解压,你尽管发过来吧。
Cache-Control: no-cache
client告诉服务端不使用缓存策略,具体的大家可以google一下Cache-Control的值,了解一些http的缓存策略。
Content-Type: text/plain
告诉服务端我发送的数据是文本类型的啦,不是什么json,二进制的
Postman-Token: 16ba727a-a71d-48ed-96b5-a79c95ab512e
client自己加的,大家可以看的出来,我是使用post man发送的
X-Lantern-Version: 5.4.7
这个……不解释
在这里http请求头已经结束了,需要换行两次,可以看到图片上有个空白的一行,然后发送post请求的payload
i am client
http post请求的payload,大家可以对照Content-Type: text/plain结合着看,是个文本数据,如果我发送的是json数据的话,大家可以猜一下Content-Type的值是啥呢?
响应
HTTP/1.1 200 OK
此部分包括协议版本,状态码,状态码描述。服务端告诉客户端我采用的协议是http1.1 响应的状态是200 OK的,同样的大家猜一下如果客户端发送一个错误的http请求这里的响应应该是啥?
Server: Tengine
告诉客户端服务端信息譬如我是Apache nginx等
Date: Tue, 16 Jul 2019 07:58:07 GMT
响应时间
Content-Type: text/plain; charset=utf-8
同请求的Content-Type
Content-Length: 2
返回的数据长度(单位字节)
Connection: keep-alive
告诉client我想保持长连接,然后如果client不接受长连接那就直接tcp的挥手了。当然tcp异常端开了,服务端可能要等到下一个tcp心跳才能感知客户端已经断开。
紧接着又是两个换行。
ok
响应的paylaod,同reqest的。
所以对于一个web服务大致时序如下图:
http时序响应码:
http的状态码可以快速的帮我们定位大致问题,一下是我据的几个例子
1、服务端tcp端口根本就没监听,你在tcp连接都建立不上,这时候一般你看到的响应是503之类的,这种就是服务不可用。你的client库自己告诉你的,其实根本没有返回
2、你请求的资源路径上没有handle处理,那服务端给你返回404,资源路径没找到
3、你发送的协议不符合http规范,400bad request
4、你使用http1.0协议请求一个http1.1的服务器,服务器会返回给你状态码101,并在响应头部告诉你服务器希望你使用的协议版本
5、你上传一个很大的文件,不知道服务器是否支持,于是你在你的请求头部添加Expect:100-continue服务端接收到你的指令希望你继续发送http请求会给你返回个100的状态码
6、301,302,303重定向相关,具体区别就是永久重定向还是单次请求重定向,浏览器会自动重定向到服务端返回指定的url
等等
下图是网上找的一个字典树的图,可以帮助大家理解后端,下期讲一下二进制协议coap,以上有错误的地方欢迎大家留言斧正。