注意:
本文摘录自《Python高效开发实战:Django,Tornado,Flask,Twisted》
作者:刘长龙 出版社:电子工业出版社
题外话:全程手打,累死,强推Markdown软件Typora。若有错误请在下方评论。
目录:
HTTP概述
HTTP,即超文本传输协议,是Internet上最主要的Web应用层标准。B/S架构的应用系统用HTTP在客户端和服务器之间传送数据。HTTP可以传送任何格式的数据,从文本到图像甚至视频流都可以通过HTTP进行传输。
HTTP流程
HTTP是Web浏览器与Web服务器之间通信的标准协议,是Internet上能够可靠地交换文件的重要基础。其基本交互流程如下图所示
每个HTTP站点都有一个服务器进程监听着TCP的HTTP端口,HTTP端口默认为80,也可由服务器进程设置为其他端口。当服务器发现有客户端建立链接并提交了一个HTTP请求(Request)后,就根据请求的内容执行相应的操作,并将结果返回给客户端(Response)。通常客户在浏览器中发起一次网络访问的步骤如下:
输入网址并按Enter键,如访问 http://www.4399.com:80/flash/199408.htm
浏览器通过域名系统查询网址的真实IP,如 210.38.3.42
向服务器210.38.3.42的80端口发起TCP连接请求并建立链接
发生HTTP请求内容,包括访问的地址 /flash/199408.htm,访问方式GET,浏览器自身的产品名等
服务器返回/flash/199408.htm中的数据作为Response发送给客户端。如果请求的不是一个文件,则服务器需要执行相应的代码,动态生成且返回给客户端。
浏览器接收到结果后关闭与服务器的TCP链接
浏览器将接收到的结果呈现在显示器上【使用系统调用等】
注意:域名解析本身不是HTTP的一部分,客户端应在向服务器建立TCP链接之前就通过DNS服务器完成域名解析工作
以上是最典型的HTTP流程,当今的HTTP版本还允许客户端在一次HTTP请求完成后不关闭TCP连接,以便之后第2次发送HTTP请求时复用该连接,以达到减少系统整体开销的目的,此技术在HTTP中叫做keep-alive
HTTP消息结构
1. Request消息结构
【请求方法】 【URL】【协议版本】
【头字段1】:值1
【头字段2】:值2
...
【头字段N】:值N
【消息体】
结构格式由两部分组成:消息头(HTTP HEAD),消息体(HTTP BODY)。消息头必须遵循上述格式,头字段可以有若干个;消息体则没有固定格式;HEAD与BODY之间以一个空行分隔。上述格式中的请求方法,URL,协议版本,头字段等都属于消息头。常用的消息体格式包括HTML,XML,JSON等。典型的Request消息如下:
GET /hello.text HTTP/1.1
Host: www.mysite.com
Accept-Language: en
上述示例是一个用GET方法访问URL http://www.,ysite.com/hello.txt页面的请求头,向服务器声明使用HTTP1.1版本,并通过Accept-Language标识了客户端接收的消息语言。本例的Request中没有消息体。
2. Response消息结构
Response是服务器根据客户端的请求包做相应处理后向客户端返回的结果,Response的格式如下
【协议版本】 【错误码】 【错误字符串】
【头字段1】:值1
【头字段2】:值2
...
【头字段N】:值N
【消息体】
消息结构仍然由两部分构成,与Request的不同点是第1行由协议版本和错误码组成。典型的Response消息如下:
HTTP/1.1 200 OK
Date: Mon, 20 Jul 2015 11:45:34 GMT
Server: Apache
Accept-Ranges: bytes
Content-Length: 31
Content-Type: text/plain
<html>
hello world
</html>
本示例中返回了一个HTTP1.1版本的消息,错误代码为200,错误字符串为OK。之后的一系列头字段标识了当前的时间,服务器的应用程序名,消息类型,消息体的长度等。消息体是一个HTML包。
3. 常用头字段
HTTP头字段以键值对的方式为服务器或者客户端提供对方的信息,比如之前用到的Accept-Language, Server等。HTTP中由一些预定义的头字段经常被用到,有经验的开发者需要熟记这些,如下表所示。表中的“方向列”,如果是Response则指示从服务器发送给客户端,如果是Request则指示从客户端发给服务器,Both表示连两个方向皆可。
字段名 | 方向 | 解释 | 可能的取值 |
---|---|---|---|
Accept | Request | 接收什么介质类型 | type/sub-type */*表示任何类型 type/* 表示该类型下的所有子类型 |
Accept-Charset | Request | 接收的字符集 | ISO-8859-1 |
Accept-Encoding | Request | 接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法 | Gzip, deflate, UTF8 |
Accept-Language | Request | 接收的语言 | En, cn |
Accept-Ranges | Request | 服务器表明自己是否接收,获取其某个实体的一部分(比如文件的一部分)的请求 | byte: 表示接受 none:表示不接受 |
Age | Response | 用该头部表明该实体从产生到现在经过了多长时间 | |
Authorization | Response | 当客户端接收到来自Web服务器的WWW-Authenticate响应时,该头部回应自己的身份验证信息给Web服务器 | Username:password |
Cache-Control | Request | 对服务器的缓存控制 | no-cache: 不要从缓存中去取,要求现在从Web服务器中去取 |
Cache-Control | Response | 对客户端的缓存控制 | Public: 可以用缓存内容回应任何用户 Private: 只能用缓存内容回应先前请求该内容的那个用户 |
Connection | Request | 对服务器的连接控制 | Close: 告诉Web服务器在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了 Keepalive: 告诉Web服务器在完成本次请求的响应后,保持连接,等待本次连接的后续请求 |
Connection | Response | 连接状态通知 | Close: 连接已关闭 Keepalive: 连接保持,等待本次连接的后续请求 |
Etag | Both | 内容唯一标识。客户端需要把服务器传来的Etag保留,在下次请求相同的URL时提交给服务器。服务器用Etag值判断同一个URL的内容是否有变化,如果有变化则发送更新的内容给客户端 | 任何值 |
Expired | Response | Web服务器表面该实体将在什么时候过期 | YYYY-MM-DD HH:MM:SS |
Host | Request | 客户端指定自己想访问的Web服务器的域名,IP地址和端口号 | IP:port |
Location | Response | 访问的对象已经被转移到别的位置了,应该到本字段指向的地址获取 | http://……. |
Proxy-Authenticate | Response | 代理服务器响应浏览器,要求其提供代理身份验证信息 | |
Proxy-Authenticate | Request | 提供自己在代理服务器中的身份信息 | Username:password |
range | Request | 需要获取对象的哪一部分内容 | bytes=1024- 获取从第1024个字节到最后的内容 |
Referer | Request | 浏览器向Web服务器表明自己是从哪个url获得当前请求中的URL的 | http://www.baidu.com |
Server | Response | 指明服务器的软件类型及版本 | Nginx/1.14 |
User-Agent | Request | 指明浏览器的软件类型及版本 | Mozilla/x.x: Windows浏览器 FireFox/x.x: 火狐浏览器 |
via | Both | 列出从客户端到服务器或者相反方向的响应经过了哪些代理服务器,它们用什么协议(和版本)发送的请求 | |
4. 常用错误代码
前面已经学习了HTTP, 每个Response的第1行中有一个整数状态码用于表达其对应Request的结果。HTTP除了约定该状态的表达方式,还约定了该状态的取值范围,约定的5类状态码如下。
1xx 信息:表明服务器已经收到Request,但需要进一步处理,请客户端等待
2xx 成功:处理成功
3xx 重定向:请求的地址已经被重定向,需要客户端重新发起请求
4xx 客户端错误:请求中提交的参数或内容有误
5xx 服务器错误:服务器处理请求时出错,一般本类错误需要联系服务器管理员处理
注意:1xx~5xx的错误为HTTP标准错误,在网站开发中如需定义自己的错误代码,则需要避开该范围
在上述5类错误中,常见的HTTP错误代码如下表所示
代码 | 解释 | 代码 | 解释 | 代码 | 解释 |
---|---|---|---|---|---|
100 | 继续等待 | 200 | 正常完成并返回 | 204 | 无内容 |
206 | 部分内容被返回 | 301 | 已移动 | 304 | 未修改 |
305 | 必须使用代理 | 400 | 语法错误 | 401 | 未授权 |
402 | 需要付费访问 | 403 | 禁止访问 | 500 | 服务器异常错误 |
501 | 未执行 | 502 | 上游的其他来源错误 | 503 | 临时过载或维护中 |
HTTP请求方法
HTTP Request包的第一个参数【请求方法】的意义在于,它能告诉服务器,客户端访问URL的目的是什么,是获取信息,上传数据还是删除信息。下表中总结了HTTP1.1中常用的访问方法及含义
访问方式的名称 | 意义 |
---|---|
DELETE | 从给定的地址中删除信息 |
GET | 从访问的地址中获取信息,即获取信息头,也获取信息体。这是互联网上最主要的一种HTTP访问方式 |
HEAD | 从访问的地址中获取信息,它与GET的区别在于,HEAD只获取信息头,不获取信息体。在Flask路由中如果声明了GET访问方式,则无需显式地声明HEAD访问方式 |
OPTIONS | 为客户端提供一种查询“本URL地址中有哪些可用的访问方式”的方法 |
POST | 客户端通过POST方法向服务器提交数据,服务器必须保证数据被完整地保存,并且服务器不允许出现重复的POST数据提交。这是HTML中通过表单(Form)提交数据所使用的URL访问方式 |
PUT | 与POST访问方法类似,PUT也是一种使客户端可以向服务器提交数据的方式。但是PUT允许客户端提交重复主键的数据,当通过PUT访问方式在服务器中发现重复主键的数据时,它会用新提交的数据覆盖服务器中已有的数据 |
基于HTTP的网站开发
经过几十年的发展,已经出现了几个成熟的处理HTTP的知名Web服务器。这些Web服务器可以解析(handles)HTTP,当Web服务器接收到一个HTTP请求(request)时,会根据配置的内容返回一个静态HTML页面或者调用某些代码动态地生成返回结果。Web服务器把动态响应(dynamic response)的产生委托(delegate)给其他一些程序,例如Python代码,JSP(JavaServerPages)脚本,Servlets,ASP(Active Server Pages)脚本等。无论它们的目的如何,这些服务器端(server-side)的程序通常会产生一个HTTP响应(Response)可以让浏览器浏览
当今几个主流的Web服务器:
- Apache
- Nginx
- IIS
- Tomcat
- JBoss
当今的主流Web服务器都实现了主流语言的可调用接口标准,这些标准如下
- CGI: Common Gateway Interface, CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。
- ISAPI: Internet Server Application Program Interface, 是微软提供的一套面向Web服务的API接口,它能实现CGI的全部功能,并在此基础上进行扩展,例如提供了过滤器应用程序的接口
- WSGI: Web Server GateWay Interface,是一套专为Python语言定制的网络服务器标准接口。
从客户端浏览器的角度来看,它的每次访问是通过HTTP访问Web服务器从而获得某种服务(下载文件,查看页面,订购商品等)的。但实际上Web服务器仅起到桥梁的作用,即将浏览器的HTTP请求解码,转换成服务器端程序能够识别的接口调用方式,然后将服务器端程序生成的返回封装成HTTP Response,并返回给浏览器。服务器端程序,Web服务器,客户端之间的关系如下图所示。
最简单的服务器端程序可以是直接读取某文件或返回固定的网页内容;稍微复杂一些的服务器端程序要处理客户端通过HTTP,URL,HTML中传入的参数,动态执行逻辑代码,在数据库或者缓存中读写数据等一系列操作,才能最终生成调用结果。