初识Http协议


  1. 很早之前,就一直想有着写一系列关于Http协议的博客文章,不过碍于自己学的知识点都非常杂乱,一直没有很系统的把Http给掌握好,很多细节的知识不知道,仅仅只局限于对其粗浅的了解。http是如此,更何况与https呢?虽然也看过一些https相关的东西,当时也觉得自己有所理解,但是并没有动手实践,具体的分析证书认证,交换秘钥,再进行对称加密通信的过程。很快就忘记了。所以现在决定写下一系列的有关http再过渡到https的文章,加上自己曾经理解,学习这一协议的过程,希望自己对于http的理解能更进一步且不那么容易忘记。也希望身边没有入门http协议的朋友能从中了解一点http相关知识。
  2. 想要理解网络协议,必须要多少会一点网络编程。这就要说起大家常说的C/S架构, B/S架构,所谓C/S架构就是客户端服务器体系,C代表了Client,S就是Server。而B/S架构,就是浏览器服务器体系,B就是Browser。其实在我看来,浏览器也属于客户端,可能是由于现在的web太火了,而单独列出这一体系。浏览器是一个功能强大的,拥有自己配置界面的配置语言(html css),和进行数据处理的脚本语言(JavaScript)。浏览器与服务器进行数据交互的过程,底层依赖的就是最基础的网络编程,依赖于Http/Https,还有比较新的websocket协议。
  3. 由于自己能力有限,不想去提太多网络编程例如TCP UDP相关的知识,那些要讲的话还得花好多时间,何况我自己还是懂点皮毛而已。怕讲太多会迷路。。。

今天仅仅是简单的介绍一下Http协议是什么,我将从浏览器敲下一个url(网址)然后回车这一过程来分析一下什么是Http,看看它的真实相貌。

  • 首先我们打开一下chrome浏览器,然后输入 https://www.baidu.com ,回车,会发现给我们显示了百度的首页,那么这是一个什么样的过程呢?首先经过的是DNS解析,解析出百度服务器IP地址,有了IP地址,就可以给百度服务器发送请求,百度服务器收到请求之后,再给浏览器响应,浏览器解析百度回应的响应,然后显示百度首页。
  • 我们可以打开浏览器自己尝试一下,F12打开调试器,选中network选项,里边可以找到百度的服务器地址。

chrome_debug

  • 上图中看到的 180.101.49.11就是百度服务器地址,443代表了端口号,因为是https协议,所以默认端口号为443,如果是http协议,默认为80。我们可以尝试直接使用IP地址对百度服务器进行请求,https://180.101.49.11 ,发现依旧能显示百度首页,这一过程仅仅略过了DNS解析。
  • 经过上面的分析,我们发现最终请求的其实是IP地址,那么URL这个东西的作用是什么呢?其实很简单,试想一下人们要记住这种毫无规律可言的IP地址是多么困难…所以URL是为了方便人们记忆以及更具有可读性。
  • 既然浏览器输入url回车之后的过程是一个请求与相应的过程,那么我们不妨自己实现一个简单的网络程序,来具体的看一下,浏览器的请求到底是什么样子。
  • 实验环境:我习惯于在linux上用vim写代码,所以准备把服务器demo写在自己的虚拟机ubuntu系统上,当然有局域网实验环境可以,必须保证浏览器所在主机ip和服务器程序所在ip网络是通的。
    下面我用python实现一个简单的TCP服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import socket

    def main():
    address = ("", 8080) # 定义地址元祖,前面为空代表监听本地所有网卡,端口号8080

    # 创建socket套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定套接字
    sock.bind(address)

    # 监听
    sock.listen(5)

    print("wait for browser connect...")
    conn_sock, peerAddr = sock.accept() # 阻塞等待浏览器连接,conn_sock为与浏览器通信套接字,peerAddr为浏览器地址信息

    recv_data = conn_sock.recv(2048) # 接收浏览器发来的数据
    print("*"*50)
    print(recv_data.decode()) # 上下分隔符,为了更清晰观察浏览器发过来的数据
    print("*"*50)

    conn_sock.close() # 关闭套接字
    sock.close()

    if __name__ == "__main__":
    main()
  • 接下来我们可以运行服务程序。显示 “wait for browser connect…”,可以看到服务程序正在等待客户端的连接,我们使用chrome输入 http://192.168.112.131:8080 ,我的ubuntu系统IP地址是192.168.112.131,冒号后边的8080是监听的端口号。然后回车…

  • 可以看到浏览器上显示拒绝了连接请求,那么我们再看服务端程序打印了什么

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    wait for browser connect...
    **************************************************
    GET / HTTP/1.1
    Host: 192.168.112.131:8080
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    If-None-Match: W/"5d46de74-939"
    If-Modified-Since: Sun, 04 Aug 2019 13:32:36 GMT


    **************************************************
  • 一大通乱七八糟的看不懂的字符串….,其实这就是Http协议报文,因为本章只是初探,暂且啥也不管管。看到了浏览器发来的请求,那么我们回一个响应试试,响应的报文就随便定义一下了。在上面的python代码关闭套接字代码前加上下面代码:

    1
    2
    3
    4
    http_head = "HTTP/1.1 200 OK\r\n\r\n"
    body = "Hello Http"
    response = http_head + body
    conn_sock.send(response.encode())
  • 我们再启动服务器,重复一下上面使用浏览器请求的步骤。神奇的发现浏览器上居然显示了 Hello Http这几个字符串,其实这就是一个简单的浏览器与服务端通过http协议通信的过程,暂且不用来管http协议报文内容,下一节再来分析http报文格式