1.1认识HTTP
超文本传输协议(Hyper Text Transfer Protocol,简称HTTP)是互联网中应用最为广泛的一种应用层协议,所有的超媒体文档都必须遵守这个标准。HTTP协议是为Web浏览器和Web服务器之间的通信设计的,但是也可以用于其他目的。HTTP协议是无状态协议,这意味着服务器不会在两个请求之间保留任何的数据或者状态。虽然它通常基于TCP/IP层,但是它可以在任何可靠的传输层上使用。
HTTP协议有多个版本,如HTTP/1.0、HTTP/1.1和HTTP/2.0,其中应用最广泛的是HTTP/1.1。
1.1.1资源与资源标识符
HTTP请求的目标称为资源,它可以是文档、照片、视频或其他任何东西。资源由统一资源标识符(URI)进行标识,在Web页面中,资源的标识和位置主要由单个URL(统一资源定位符)给出URL通常被称为Web网址,是最常见和使用最多的URI。当我们在浏览器的地址栏中输入URL或者单击超链接时,就确定了要获取的资源的地址。
1.1.2URL组成部分作用
- 协议类型名称: 表示浏览器必须使用的协议,通常是HTTP协议或其安全版本HTTPS。
- 域名: 表示正在请求哪个Web服务器,也可以直接使用主机地址。
- 端口号: 用于表示Web服务器上的资源入口,如Web服务器使用HTTP协议的标准端口(HTTP为80,HTTPS为443)来授予对其资源的访问权限。
- 资源路径: Web服务器上资源的路径,在Web的早期,这样的路径代表了Web服务器上的物理文件位置,如今它主要是由Web服务器处理的抽象标识。
- 查询参数: :用&符号分隔的键值对。在将资源返回给用户之前,Web服务器可以使用这些参数来执行额外的操作。每个Web服务器都有自己的参数规则,了解特定Web服务器如何处理参数的唯一可靠方法是询问Web服务器的所有者或应用程序的开发者。
1.1.3HTTP请求与响应
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,imag/webp,image/apng,/;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Host: www.example.com
If-Modified-Since: Fri, 09 Aug 2013 23:54:35 GMT
If-None-Match: "1541025663"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0(X11;Fedora;Linuxx86_64)AppleWebKit/537.36(KHTML, like Gecko) Chrome/72.0.1
请求头的简要说明:
- Accept: 客户端希望接受的数据类型,比如Accept: text/html代表客户端希望接受的数据类型
是HTML类型。 - Accept-*: 指定客户端可接受的内容,比如Accept-Encoding用于指定可接受的编码,AcceptLanguage用于指定可接受的语言类型。
- Content-Type: 互联网媒体类型(简称MIME类型),代表具体请求的媒体类型信息(比如text/html代表HTML格式,image/gif代表GIF图片,application/json 代表JSON类型)。
- Host: 指定请求资源的域名(或IP)和端口号,内容为请求URL的原始服务器或网关的位置。
- Cookie: 可以理解为在HTTP协议下,服务器或其他脚本语言维护客户端信息的一种方式,是保存在客户端(比如浏览器)的文本文件。Cookie中往往包含客户端或者用户的相关信息。
- Referer: 记录上一次访问的页面地址,也可以理解为标识此次请求的来源URL。
1.1.4 HTTP状态码
HTTP响应是指服务器端根据客户端的请求返回的信息。HTTP响应由状态码、响应头和响应正文组成。状态码是一个3位数字(如200),它的第一位代表了不同的响应状态。响应状态共有5种,含义如下。
- 1代表信息响应类,表示接收到请求并且继续处理,这类响应是临时响应
- 2代表处理成功响应类,表示动作被成功接收、理解和接受。
- 3代表重定向响应类,为了完成指定的动作,必须接受进一步处理。
- 4代表客户端错误,表示客户请求包含语法错误或者是不能正确执行的请求。
- 5代表服务器端错误,服务器不能正确执行一个正确的请求。
状态码 | 含义 |
---|---|
101 | 协议切换,客户端要求服务器切换协议并且服务器已确认切换 |
200 | 服务器已成功处理了请求 |
201 | 请求已经被实现,有一个新的资源已经依据请求的需要而建立,且其 URI 已经随 Location 头信息返回 |
204 | 服务器成功处理了请求,但没有返回任何内容 |
301 | 请求的网页已永久移动到新位置,即永久重定向 |
302 | 请求的网页临时跳转到其他页面,即临时重定向 |
305 | 请求的资源必须通过指定的代理才能被访问 |
400 | 服务器端无法解析该请求 |
401 | 未授权,即当前请求需要用户验证 |
403 | 服务器已经接收到此请求,但是拒绝执行 |
404 | 失败,相应资源不存在 |
500 | 服务器内部错误,无法完成请求 |
502 | 作为网关或者代理的服务器在尝试执行请求时,从上游服务器接收到无效的响应 |
1.1.5响应头域及其含义
响应头 | 含义 |
---|---|
Allow | 服务器支持的请求方法(比如GET、POST等) |
Content-Encoding | 文档的编码(encode)方法。只有在解码之后,才可以得到Content-Type头指定的内容类型 |
Content-Length | 内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据 |
Content-Type | 文档的MIME类型。默认为text/plain,但通常需要显式指定为text/html |
Date | 消息被发送时的日期和时间(时间格式为GMT) |
Expires | 指定一个日期/时间,超过该时间则认为此回应已经过期 |
Last-Modified | 所请求的对象的最后修改日期 |
Location | 进行重定向或在创建某个新资源时指定位置 |
Refresh | 浏览器应该在多少时间之后刷新文档,单位为秒 |
Server | 服务器名称及版本 |
Set-Cookie | 设置与页面关联的Cookie |
Status | 本次请求的状态码 |
2.1认识WebSocket
WebSocket是一种在单个TCP连接上进行全双工通信的协议,被广泛应用于对数据实时性要求较高的场景,如体育赛事播报、股票走势分析、在线聊天等。
WebSocket协议使客户端和服务器端之间的数据交换变得更加简单,它允许交互双方创建持久连接,同时支持服务器端主动向客户端推送数据。
2.1.1WebSocket握手
与HTTP协议不同的是,WebSocket协议只需要发送一次连接请求。连接请求的完整过程被称为握手,即客户端为了创建WebSocket连接而向服务器端发送特定的HTTP请求并声明升级协议。WebSocket是独立的、创建在TCP上的协议,双端通过HTTP/1.1协议进行握手,握手成功后才会转为WebSocket协议。
使用WebSocket协议进行通信时,客户端与服务器端的交互顺序如下:
- 客户端发起握手请求。
- 服务器端收到请求后验证并返回握手结果。
- 连接建立成功,可以互相发送消息。
设客户端发出一个符合握手约定的HTTP请求,那么服务器端需要先对信息进行验证,并将握手结果回复给客户端。服务器端返回的握手结果包含状态码和当前所用的协议,返回信息的含义如下:
- Status Code代表本次握手结果,状态码中的101表示连接成功。
- Connection和Upgrade表明当前所用协议。
- Sec-WebSocket-Accept是经过服务器确认并加密过后的Sec-WebSocket-Key。
如果客户端收到如下响应,那么说明握手成功:
Status Code: 101 Web Socket Protocol Handshake
Sec-WebSocket-Accept:T5ar3gbl3rZJcRmEmBT8vxKjdDo=
Upgrade: websocket
Connection: Upgrade
WebSocket示例:
import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket
async def startup(uri):
async with AioWebSocket(uri) as aws:
# 初始化 aiowebsocket 库的连接类
converse = aws.manipulator
# 设定需要向服务器发送的信息
message = b'AioWebSocket - Async WebSocket Client'
while True:
# 不断地向服务器发送信息,并打印输出信息的内容和时间
await converse.send(message)
print('{time}-Client send: {message}'.format(time=datetime.now()
.strftime('%Y-%m-%d %H:%M:%S'), message=message))
# 不断地读取服务器推送给客户端的信息,并打印输出信息的内容和时间
mes = await converse.receive()
print('{time}-Client receive: {rec}'.format(time=datetime.now()
.strftime('%Y-%m-%d %H:%M:%S'), rec=mes))
if __name__ == '__main__':
remote = 'wss://echo.websocket.org'
try:
# 开启事件循环,调用指定的方法
asyncio.get_event_loop().run_until_complete(startup(remote))
except KeyboardInterrupt as exc:
logging.info('Quit.')