HTTP 协议

Hi, I'm Shendi.

这次我将我多年的HTTP协议笔记做个总结

后续可能会持续完善...


如果想要实战部分练练手可以看此篇文章: https://blog.****.net/qq_41806966/article/details/106322292

 

目录

HTTP

请求

解析

请求的请求体

笔记内容

响应

响应体

笔记

 重定向

图标

 


 

HTTP

超文本传输协议(HTTP,HyperText Transfer Protocol)

 

这里对HTTP协议的介绍直接引用百度百科了,里面写的也比较详细

https://baike.baidu.com/item/http/243074?fr=aladdin

http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使得开发和部署是那么的直截了当

HTTP协议是基于TCP的,并且用于浏览器与Web服务器上

目前常用的HTTP版本为 1.1

HTTP协议分为 请求和响应


请求

当我们客户端访问服务端,这个操作为请求(浏览器访问网站)

 

我们可以来实际测试一下,看一下请求的数据是什么样的

通常我们使用浏览器访问的时候会默认带 http,并且默认访问的是 80 端口

https 是 443 端口

这里使用的是Java,就是一个简单的TCP套接字,开启的 80 端口,接收数据

HTTP 协议

运行这个程序,并使用浏览器访问(本机的地址是 127.0.0.1, 域名为 localhost)

当访问后,控制台输出如下

HTTP 协议

并且程序还在运行(卡在了循环中)

 

解析

  • 通过上面的输出可以看出,第一行是请求协议头
  • GET / HTTP/1.1
    • GET 是请求类型,然后一个空格 / 代表请求资源的路径,我用浏览器直接访问的 localhost 所以为 /,然后一个空格 HTTP1.1代表协议版本
    • 可以再来尝试一下,例如我通过浏览器访问 localhost/abcdefg
    • HTTP 协议
    • HTTP 协议
  • 需要注意,我们在控制台看到的换行效果是两个字符,为 \r\n,所以每一行的后面都有一个看不见的 \r\n
    • 可以开 debug 看一下, \r 的值为13,\n 的值为10
    • HTTP 协议
    • 数一下,第21个的确是换行的空部分
  • 对于请求类型,一共有八种,常用的为 GET 和 POST
  1. opions            返回服务器针对特定资源所支持的HTML请求方法,或web服务器发送*测试服务器功能(允许客户端查看服务器性能)
  2. Get                 向特定资源发出请求(请求指定页面信息,并返回实体主体)
  3. Post               向指定资源提交数据进行处理请求(提交表单、上传文件),又可能导致新的资源的建立或原有资源的修改
  4. Put                 向指定资源位置上上传其最新内容(从客户端向服务器传送的数据取代指定文档的内容)
  5. Head              HEAD就像GET,只不过服务端接受到HEAD请求后只返回响应头,而不会发送响应内容。当我们只需要查看某个页面的状态的时候,使用HEAD是非常高效的,因为在传输的过程中省去了页面内容
  6. Delete            请求服务器删除request-URL所标示的资源*(请求服务器删除页面)
  7. Trace             回显服务器收到的请求,主要用于测试和诊断
  8. Connect         HTTP/1.1协议中能够将连接改为管道方式的代理服务器
  • 对于请求路径,如果资源不是一个具体的文件(比如接口之类的) 则后面需要以 / 结尾,根路径直接是 /

从第二行开始到结尾,我们发现都带一个冒号 :

这是请求头,通常最少会有一个 HOST 请求头表示自己请求的主机名,服务端也可以通过这个来进行过滤一些非正常请求

每一个请求头都是键值对形式 例如 A: B, 冒号左边是键,右边是值,并且每一个请求头后面都带着一个 \r\n(换行)

在请求头结尾 也会带一个 \r\n,所以,我们可以通过判断数据的尾巴是不是 \r\n\r\n 来判断是否到达请求头结尾

关于更多请求头可以直接参考百度上的,那个比较全

 

于是之前的一直卡在死循环的问题就解决了,只要判断结尾就ok.

于是我改变代码,我使用了自己封装的包,有需要的也可以去我的github上面获取: https://github.com/1711680493/ShendiKit

HTTP 协议

 

再次运行测试,发现程序已经可以正常停止,并且浏览器上也得到了及时的反应

 

HTTP 协议

HTTP 协议

 

请求的请求体

这个是我踩过的坑

通常来说,请求一般是没有请求体的,但是在某些情况下会有

比如 POST 请求的参数,参数是在请求体内

请求的请求体都会带一个请求头,为 Content-Length,表示请求体的长度

我们可以通过判断是否有这个请求头来判断是否有请求体

(可能还有一些情况,目前我只遇到这一种,有补充的可以在评论区留言)

 

笔记内容

下面是我笔记的内容,我直接贴出来了(比较简洁)

请求
        第一句应为请求资源类型等(每一行代表独立的一行(换行))
        GET / HTTP/1.1\r\n
            请求类型(GET/POST...) 请求路径(例如根路径为/ get会带参数) HTTP/1.1(Http版本)
        请求头...(每个请求头后都要加\r\n 换行)
        \r\n
            结尾是两个换行,因为请求头后必须带一个,所以这里只需要加一个
        请求体
            注: 请求一般是没有请求体的,但是POST请求中的参数会在请求体中,以及模拟的Http请求发送的数据也在请求体中
            请求头有 Content-Length 代表有请求体

 

响应

请求是客户端访问服务端,那么响应对应的就是 客户端访问服务端,服务端将信息处理返回给客户端

通常一次 http 操作 就是一次请求+响应,长连接除外

同样,我们先来测试一下,写一个TCP套接字请求某网来获取数据查看一下

HTTP 协议

启动,在控制台的结果如下

HTTP 协议

内容比较多,只看上面一部分

首先,与请求对应的,第一行也是协议头

  • HTTP/1.1 200 OK
  • 第一个为协议版本,第二个为响应状态,第三个为响应信息
  • 主要的是响应状态,200代表正常,服务器出现错误则会为500...

从第二行开始 一直到换行的那个地方为响应头

与请求头一样,每一个响应头后面都带 \r\n 并且 结尾是 \r\n 可以通过 \r\n\r\n 来判断响应头结尾

 

与请求相反,响应一般都携带响应体

需要注意的是,响应头并不一定携带 Content-Length 响应头

如果没有此响应头,则以 \r\n0\r\n\r\n 结尾,有则读取指定长度

 

测试一下,稍微修改一下服务端,让他返回数据

我们先直接返回状态为 500 的试一下

HTTP 协议

浏览器访问,界面如下

HTTP 协议

我们改为200,并返回一串字符串,带上请求头

HTTP 协议

浏览器显示如下

HTTP 协议

 

响应体

与请求相反,响应一般都有响应体

但是在某些情况下没有(踩坑)

没有消息体的204,205,304,以\r\n\r\n结尾
    204    No Content
        服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息
        204响应禁止包含任何消息体,因此以消息头后第一个空行结尾
    205 Reset Content
        服务器成功处理了请求,与204不同,返回此状态码的响应要求请求者重置文档视图
        该响应主要是用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入
    304 Not Modified
        如果客户端发送了一个带条件的GET请求,且该请求已被允许,
        而文档的内容自上次访问并没有改变,则返回此状态码

笔记

HTTP/1.1 200 OK
            第一句话为请求状态
            协议类型 状态 信息
        响应头,与请求一致,每个响应头后面都带\r\n
        \r\n
        响应体
            如果响应头有Content-length 则使用此获取 否则判断结尾来获取
            如果没有,则结尾为 \r\n0\r\n\r\n(最好是有Content-Length,某些浏览器不能解析)
            特定状态没有响应体

 

 重定向

响应状态为 302 代表重定向(暂时转移),也就是获取到302后直接跳转页面

响应状态为 301 代表永久重定向,当第一次获取到后就会将之存起来,下次直接访问重定向的目标

 

 

图标

浏览器在请求时会请求图标 /favicon.ico,所以第一次一般有两个请求