Python 高级 9 HTTP协议

浏览器访问服务器的过程、HTTP协议、开发者工具、HTTP请求报文协议分析、HTTP响应报文协议分析、长连接和短连接、案例-模拟浏览器的功能实现

1.浏览器访问服务器的过程

目标

  知道浏览器访问服务器的过程

  知道URL的含义

  知道域名和ip的关系

<1>浏览器请求的基本流程如下:

浏览器访问百度服务器程序的通信流程

  在浏览器的地址栏输入网址(url)

  当用户输入回车的时候,域名解析服务器会把域名解析成一个对应的ip地址

  和百度服务器的web应用程序建立连接

  发送http协议格式的请求数据

  百度服务器的web应用程序会根据请求在本地获取请求的资源数据

  百度服务器的web应用程序会发送http协议格式的响应数据

http: 默认使用端口号是80

https: 默认使用端口号443

http协议的工作模式: 请求+响应的模式,先有请求然后再有响应

图1 - mini-web服务器工作流程

  1. 用户输入网址.

  2. 浏览器请求DNS服务器, 获取域名对应的IP地址和端口号.

  3. 请求连接该IP地址服务器.

  4. 发送资源请求. (HTTP协议)

  5. web服务器接收到请求, 并解析请求, 判断用户意图.

  6. 获取用户想要的资源.

  7. 将资源返回给web服务器程序.

  8. web服务器程序将资源数据通过网络发送给浏览器.

  9. 浏览器解析请求的数据并且完成网页数据的显示.

<2>网址是什么呢?

网址有称为URL,URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址。

URL的组成部分大概分为三部分:

  协议头部分

  域名部分

  资源路径部分

比如: http://news.china.com.cn/2018-06/12/content_52060465.htm URL的格式为: http://: 协议部分 news.china.com.cn: 域名部分 /2018-06/12/content_52060465.htm:资源路径部分

<3>域名是什么呢?

我们在访问一台服务器的时候, 需要记住该服务器的IP地址, 由于IP地址不利于人们记忆, 所以推出的域名技术. 域名是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称, 用于在数据传输时标识计算机的位置.

域名可以用来表示一个单位、机构或可以利用个人在 Internet上 的确定的名称或位置. 域名是惟一的. 客户可以利用这个名字找寻有关的产品和服务信息.

<4>DNS 是什么呢?

由于我们用域名来标识计算机的位置, 但是我们前面讲过, 网络上标识主机的唯一标识是IP地址, 所以就需要记录一下, 一个域名和IP地址的对应关系, 这个对应关系就存储在DNS服务器中, 当我们向DNS发出请求时, DNS会返回给我们域名所对应的IP地址.

域名: 方便记忆某台电脑的主机地址,域名最终对应的是一个ip地址

DNS: 域名解析服务器, 当使用访问某个网址的时候,域名解析服务器会把域名解析成一个对应的ip地址

小结

  浏览器访问服务器其实就是请求和响应的过程

  URL通俗理解就是请求资源在网络中的地址

  通过域名可以解析出来一个ip地址,域名是方便大家记忆某台主机地址的

2.HTTP协议

目标

  知道http协议的作用

<1>HTTP协议简介

HTTP协议就是超文本传输协议(HyperText Transfer Protocol),通俗理解是浏览器和web服务器传输数据格式的协议,HTTP协议是一个应用层协议。

HTTP协议是基于TCP协议的,发送数据之前需要建立好连接

HTTP是万维网的数据通信的基础。设计HTTP最初的目的是为了提供一种发布和接收HTML页面<网页>的方法。

HTTP协议的制作者是蒂姆·伯纳斯-李,他供职于CERN(欧洲核子研究组织)

  1991年发布的0.9版,该版本极其简单,只有一个GET请求方法

  1996年5月,HTTP/1.0版本发布

  1997年1月,HTTP/1.1版本发布,目前使用就是HTTP/1.1版本

<2>网络传输-TCP/IP四层模型

TCP/IP模型又称为TCP/IP协议族,是一系列网络协议的总称。TCP/IP模型一共包括几百种协议,制作协议的目的,就是保证计算机之间可以按照一定格式进行数据通信。

  1. 网络接口层(数据链路层/网络接口层):包括操作系统中的设备驱动程序、计算机中对应的网络接口卡.

  2. 网络层:处理分组在网络中的活动,比如分组的选路.

  3. 传输层:主要为两台主机上的应用提供端到端的通信.

  4. 应用层:负责处理特定的应用程序细节.

<3>HTTP协议的工作模式

HTTP协议的工作模式是一次请求(request)和一次响应(response)的模式

3.使用谷歌开发者工具查看HTTP协议的通信过程

目标

  知道谷歌浏览器开发工具的使用流程

这里介绍 谷歌开发者工具使用

windows和Linux平台按F12调出开发者工具, MAC选择 视图 -> 开发者工具。

在 web 应用中, 服务器把网页传给浏览器, 实际就是把网页的 HTML 代码发送给浏览器, 浏览器解析显示出来. 而浏览器和服务器之间的传输应用层协议就是 HTTP. 所以:

  HTML 是一种用来定义网页的文本, 会 HTML 就可以编写网页.

  HTTP 是用来在网络上传输 HTML 文本的协议, 用于浏览器和服务器的通信.

Chrome 浏览器提供了一套完成的开发者工具, 很适合 web 开发者.

图4 - 打开开发者工具

图5 - 开发者工具界面

  元素(Elements):用于查看或修改HTML元素的属性、CSS属性、监听事件、断点等.

  控制台(Console):控制台一般用于执行一次性代码, 查看JavaScript对象, 查看调试日志信息或异常信息.

  源代码(Sources):该页面用于查看页面的HTML文件源代码、JavaScript源代码、CSS源代码, 此外最重要的是可以调试JavaScript源代码, 可以给JS代码添加断点等.

  网络(Network):网络页面主要用于查看 header 等与网络连接相关的信息.

注意:

Network 中的每一项就是一次请求/响应过程, 点击每一项, 可查看本次请求响应的报文信息.

4.HTTP 请求报文协议分析

目标

  知道HTTP协议请求报文的格式

首先,我们通过开发者工具查看一下请求报文的格式.

Request Headers 中就是请求的报文数据内容. 下面就是我们要请求的报文示例数据:

GET / HTTP/1.1

Host: localhost:10000

Connection: keep-alive

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7

<1>GET / HTTP/1.1 叫做请求行. 里面包含3个信息, 以空格隔开,

  第一个叫做请求方法, 除了 GET 方法之外, 还有 POST 方法, 除此之外还有其他方法, 这两种最常用. GET 主要用于从服务器获得数据, POST 主要用于从浏览器提交数据到服务器. 比如像百度首页提供的上传图片的功能, 就是用POST方式.

  第二个表示请求的资源路径. 当请求的URL是 https://www.baidu.com/, 那么我们会发现 路径会显示 '/', 那么如果请求的URL是 https://www.baidu.com/index.html, 我们会发现路径显示是 '/index.html'.

  第三个表示 HTTP 协议的版本, 那么既然有 1.1版本, 前置版本肯定是1.0了,那么两个版本有什么区别呢? 1.1版本比1.0的版本主要多个一些请求方法等扩充协议的内容.

<2>请求头. 除了第一行之外, 剩下的所有数据的格式都是类似的.

  Host 表示浏览器要请求的主机地址. 这服务器ip地址,如果端口号不显示,默认使用:80

  Connection 表示浏览器和服务器之间的连接方式, 浏览器和服务器连接是长连接( keep-alive)还是短连接

  Cache-Control: 缓存方式 max-age=0表示不缓存

  User-Agent 用户代理, 客户端应用程序的类型, 指定User-Agent可以做到初步反爬 。我们使用谷歌浏览器和火狐浏览器分别请求百度, 那么会发现 User-Agent 的值是不一样的, 它主要是用于浏览器告诉服务器自己的身份, 比如浏览器端使用的操作系统是什么版本, 浏览器是什么版本等等. 服务器端为什么需要知道这个信息呢? 我们后面会讲到爬虫,爬虫程序主要是从服务器端获取数据, 那么服务器端就会有反爬机制, 服务器不希望爬虫来获取数据, 所以通过该项可以知道客户端是否是爬虫程序. 如果爬虫程序想伪装成一个浏览器的请求, 就必须设置此项.

  Accept 表示浏览器告诉服务器, 自己能够接收并识别的文件类型.

  Accept-Encoding 表示浏览器能够处理的压缩方式. 为什么需要压缩呢? 当网页数据量大的时候, 压缩之后可以提高传输速率, 提高用户体验.

  Accept-Language 浏览器可以接收的文本语言, 如果非中文编码可能会出现乱码.

  Cookie:  客户端用户身份的一个表示

小结

注意:

form data:请求体(客户端给服务器发送的数据),HTTP请求报文可以分为GET请求和POST请求报文,要注意的是GET请求没有请求体,POST请求有请求体信息

5.获取请求报文原数据

目标

  知道浏览器使用的是http协议并能发送请求报文数据

需求

使用python语言写一个tcp服务端程序,让浏览器访问自己的服务端程序,获取浏览器的请求报文数据

参考代码

# tcp服务端的程序

import socket

# 判断是否是程序的入口

if __name__ == '__main__':

    # 创建tcp服务端socket

    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定端口号

    tcp_server_socket.bind(("", 8080))

    # 设置监听

    tcp_server_socket.listen(128)

    # 等待接收客户端连接请求

    service_client_socket, ip_port = tcp_server_socket.accept()

    # 接收浏览器请求的原始报文数据

    recv_data = service_client_socket.recv(4096)

    print(recv_data)

    service_client_socket.close()

    tcp_server_socket.close()

小结

http原始请求报文数据请求行、请求头之间会有\r\n特殊数据

6.HTTP 响应报文协议分析

如何使用开发者工具查看请求报文, 以请求 Baidu.com 为例:

HTTP/1.1 200 OK

Connection: Keep-Alive

Content-Encoding: gzip

Content-Type: text/html; charset=utf-8

Date: Wed, 14 Mar 2018 09:52:48 GMT

Server: BWS/1.1

<1>第一行 HTTP/1.1 200 OK 叫做响应行,

共分成3部分, 第一部分 HTTP/1.1 表示 HTTP协议的版本, 第二部分是一个数字, 这个数字表示响应状态码, 用户向服务器发出了请求, 如果服务器正常返回响应报文, 那么状态码一般都是200, 第三部分的 "OK" 表示原因短语, 表示对前面状态码的简单描述. 这里需要说的是, 响应的状态码除了 200 之外, 还有其他的状态码, 下面是常见的状态码:

          ■ 302 redirect, 我们通过 302 状态码可以指示浏览器跳转到某一个 URL.

      404 NOT FOUND, 当我们访问一个不存在的 URL 时, 一般会返回404状态码, 告诉浏览器, 你访问的 URL 是不存在的.

      500 Internal Server Error, 服务器遇到了一个未曾预料的状况, 导致了它无法完成对请求的处理. 一般来说, 这个问题都会在服务器端的源代码出现错误时出现.

<2>响应头

Server: nginx/1.10.2 服务器的名称

Date: Thu, 06 Sep 2018 04:11:11 GMT 服务器的时间: 格林威治时间, 相当于0时区

Content-Type: text/html;charset=UTF-8 服务器告诉客户端浏览器响应内容的文本格式及编码格式

Transfer-Encoding: chunked 表示服务器发送给客户端的数据大小不确定,如果发送数据完成会有一个特殊的标识数据\0\r\n , Content-Length: 100 明确告诉客户端发送数据的长度, 两者会有其一

Connection: keep-alive 表示连接状态,  keep-alive表示长连接

X-Application-Context:application:production:6202 服务器程序程序员自己设置的响应头信息

Content-Language:zh-CN 服务器告诉客户端支持的语言类型

<3>空行(\r\n)

<4>响应体(查看响应体数据选择response选项卡)

小结

HTTP协议响应报文分为4部分,每部分之间使用\r\n进行分割

  响应行

  响应头

  空行(\r\n)

  响应体

7.长连接和短连接

目标

  知道长连接和短连接的特点

在HTTP/1.0中, 默认使用的是短连接.也就是说, 浏览器和服务器每进行一次HTTP操作, 就建立一次连接, 但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的 Web 页中包含有其他的Web资源,如js文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。

但从 HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:

长连接 Connection:keep-alive

短连接 Connection:close

在真正的读写操作之前,server与client之间必须建立一个连接,

当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,

连接的建立通过三次握手,释放则需要四次握手,

所以说每个连接的建立都是需要资源消耗和时间消耗的。

<1>TCP短连接

模拟一种TCP短连接的情况:

  client 向 server 发起连接请求

  server 接到请求,双方建立连接

  client 向 server 发送消息

  server 回应 client

  一次读写完成,此时双方任何一个都可以发起 close 操作

一般都是 client 先发起 close 操作。当然也不排除有特殊的情况。

从上面的描述看,短连接一般只会在 client/server 间传递一次读写操作!

<2>TCP长连接通信过程

  client 向 server 发起连接

  server 接到请求,双方建立连接

  client 向 server 发送消息

  server 回应 client

  一次读写完成,连接不关闭

  后续读写操作...

  长时间不操作之后client发起关闭请求

<3>TCP长/短连接的优点和缺点

  长连接可以省去较多的TCP建立和关闭的操作,节约时间。但是如果用户量太大容易造成服务器负载过高最终导致服务不可用

  短连接对于服务器来说实现起来较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但是如果用户访问量很大, 往往可能在很短时间内需要创建大量的连接,造成服务器响应速度过慢

小结

  长连接: 连接建立成功后,可以发送多次请求和响应,等双方不进行通信的时候,服务端做好断开连接的操作

  短连接: 连接建立成功后,一次请求和响应完成以后连接就会断开,每次发送请求需要先建立好连接

  长连接减少了用户的等待时间,提升了访问速度,但是增加了服务端的资源开销

  短连接不会占用服务端过多的资源,但是增加了用户的等待时间,减慢了访问速速

8.案例-模拟浏览器的功能实现

目标

  掌握请求报文和响应报文的发送格式

案例需求

模拟浏览器请求web服务器的网页过程,使用TCP实现 HTTP协议(请求报文格式和响应报文格式)。

案例实现

import socket

if __name__ == '__main__':

    # 创建tcp客户端套接字

    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 建立连接

    tcp_client_socket.connect(("tlias3.boxuegu.com", 80))

    # 请求行

    request_line = "GET / HTTP/1.1\r\n"

    # 请求头

    request_header = "Host: tlias3.boxuegu.com\r\nConnection:close\r\n"

    # 准备http请求报文数据

    request_content = request_line + request_header + "\r\n"

    # 发送http请求报文数据

    tcp_client_socket.send(request_content.encode("utf-8"))

    # 定义二进制响应数据的类型

    result = b""

    # 接收服务端http响应报文数据

    while True:

        # 提示: 服务端断开连接,recv会解阻塞,返回的数据长度0

        # 提示: 以后可以通过Content-Length判断服务端发送数据的长度

        recv_data = tcp_client_socket.recv(1024)

        if recv_data:

            # 表示接收到了数据

            result += recv_data

            # print(result)

        else:

            break

    # 显示原始的响应报文数据

    print(result)

    # 解码 : 把二进制数据转成字符串

    response_content = result.decode("utf-8")

    # 根据指定标识数据进行分割

    response_list = response_content.split("\r\n\r\n", 1)

    # response_content.split("\r\n\r\n", maxsplit=1)

    print(len(response_list))

    print(response_list[1])

    # 关闭套接字

    tcp_client_socket.close()

小结

  注意http请求报文的格式: 请求行 + 请求头 + \r\n + 请求体(可选)

      请求行包括 1.请求方法 2.资源路径 3.http协议版本

      请求头常用 1.Host:ip:port 2.Conection:keep-alive

  注意http响应报文的格式: 响应行 + 响应头 + \r\n + 响应体

      响应行包括 1.http协议版本 2.响应状态 3.响应状态的简单描述

      响应头常用 1.Server:服务器版本 2.Content-type:text/html;charset=utf-8 3.Connection:keep-alive

你可能感兴趣的:(Python 高级 9 HTTP协议)