python网络编程——HTTP客户端

1.Python客户端库。

       urllib和requests是Python对HTTP协议的应用,使用的两个库。urllib是Python的标准内置库,requests是一个比urllib更强大的第三方库。下面我们会使用一个域名为http:httpbin.org的小型测试网站来测试这两个HTTP客户端。
python网络编程——HTTP客户端_第1张图片python网络编程——HTTP客户端_第2张图片
       上面两张图片分别是使用requests和urllib两个库进行http请求访问http://httpbin.org/headers,从图中我们已经可以看出来两个库的不同点了,requests支持gzip和deflate两种压缩格式的HTTP响应,而urllib则不支持。还有,requests能够自己确定正确的解码方式,并将HTTP响应从原始字节转换为文本;而urllib库则只会返回原则是字节,用户需要自己进行解码。

2.端口、加密与封帧。

       80端口是用于纯文本HTTP会话的标准端口。而有些客户端则希望首先协商一个加密的TLS(安全传输层协议)会话。一旦加密连接建立完成,就使用HTTP进行通信。这是超文本传输安全协议(HTTPS,Hypertext Transfer Protocol Secure)的一个变形,此时使用的标准端口是443端口。
       TLS的目的并不仅仅是保护数据在传输过程中不被窃听,他也会对客户端连接的服务器进行验证。当然如果客户端也提供证书的话,TLS也允许服务器对客户端身份进行验证。
       在HTTP中,客户端首先向会向服务器发送一个获取文档的请求(request)。一旦发送完整个请求,客户端就会进行等待,直到从服务器接收到完整的响应为止。目前使用的HTTP/1.1版本中还不允许客户端在未收到完整的响应之前进行第二个请求。
       HTTP有一种很重要的平衡——请求和响应采取了相同的封帧规则。在对消息体进行封帧时,有三种不同的方法可供选择。

  • 最常见的封帧方法就是提供一个Content-Length头,它的值是一个十进制整数,表示消息体包含的字节数。该方法实现起来非常简单。客户端可以简单地在徐怒汉中不断运行recv()调用,直到接收到的字节总数与Content-Length中声明的字节数相等为止。然而有时候数据是动态生成的,此时无法在头信息中声明Content-Length头,只有在整个过程完成之后,才能够确定消息体的长度。
    python网络编程——HTTP客户端_第3张图片
  • 如果在头信息中指定Transfer-Encoding头,并将其设置为chunked(分块),那么可以激活一个更为复杂的封帧机制。该机制不会在消息体前面指定该块的长度,而是将消息体分成一系列较小的消息快,在每个块前使用一个前缀来指定该块的长度。每个块中至少包含如下部分:一个表示块长度的十六进制数(与使用十进制表示的Content-Length有所不同)、两个字符CR-LF、一个与给定长度相符的数据块以及最后的两个字符CE-LF。在所有块结尾,是哟个一个长度为0的块来表示消息的结束。长度为0的块是最小的块,包含数字0、两个字符CR-LF以及最后的两个字符CR-LF。发送者可以在块长度和CR-LF之间插入一个分号,然后指定应用于该块的extension选项。在最后一个块中,发送者可以在用0表示的块长度和CR-LF之间添加最后一些HTTP头。
  • 另一个可以代替Content-Length的方法略显突兀。服务器可以指定Connection: close,然后就能够随意发送任意大小的消息体,发送完毕后关闭TCP套接字。该方法引入了一个危险:客户端无法判断套接字是因为成功发送了完整的消息体而关闭,还是由于服务器或网络错误而提前关闭。此外,使用这种方法时,客户端每发送完一个请求都需要重新连接服务器,这降低了协议的效率。

3.方法。

       HTTP请求中的第一个单词指定了客户端请求服务器时使用的操作类型。(如下图)GET和POST是两种最常见的方法。
python网络编程——HTTP客户端_第4张图片
       GET和POST这两种基本方法提供了HTTP的基本“读”和“写”操作。
       当我们在浏览器中输入HTTP的URL时,使用的就是GET方法。它请求服务器将请求路径指向的文档作为响应发送回浏览器。GET方法不包括消息体。HTTP标准规定,任何情况下都不能允许客户端通过GET方法修改服务器上的数据。像?q=python或者?result=10这样附加到请求路径后面的任何参数都只能修改返回后的文档,而不能修改服务器上的数据。这一限制使得客户端能够在第一次请求常识失败时安全地重新尝试GET,也能够将GET的响应存入到缓存中。除此之外,还能使我们在运行网络抓取程序时,安全地访问任意数量 的URL,而不必担心网络抓取程序会在其遍历的网站上创建或删除内容。
       当客户端希望向服务器提交新数据时,就会使用POST方法。传统的Web表单通常使用POST来提交客户端的请求(除非它们直接将表单数据复制到URL中)。面向程序员的API同样使用POST来提交新文档、评论以及数据库行。两次运行同一个POST会在服务器上进行两次相同的操作,因此既不能将POST操作的结果存入缓存以提高后续重复操作的速度,也不能在没有接收到响应的时候自动重试POST。
       在使用这两个方法时也体现出了requests和urllib两个库的不同,标准库的urlopen()方法隐式地选择了HTTP方法。如果调用者指定了一个数据参数,那么使用POST方法,否则使用GET方法。因为HTTP方法的正确使用对于客户端和服务器设计安全性都是非常重要的,所以这并不是一个明智的选择。Requests库的选择就好多了,它为不同的基础方法都提供了get()和post()方法。
       除了这两种方法之外还有其他的方法,都可以归结为本质上类似于GET的方法和本质上类似POST的方法。

4.路径与主机。

       第一个版本的HTTP允许只在请求中包含方法名和路径。
在这里插入图片描述
       这在互联网早起没有问题,因为当时每台服务器上只会托管一个网站。但是后来管理员开始希望在大型HTTP服务器上部署几十上百个网站,此时上述做法就行不通了。如果只提供路径的话,服务器难以推测用户在URL中输入的是哪个主机名?尤其是现在几乎每个网站都有/这样的路径。
       解决方法就是至少要强制使用Host头。现代HTTP协议也要求提供协议版本,一个请求至少需要提供下述信息:
在这里插入图片描述
       如果客户端没有提供Host头支持在URL中使用的主机名,许多HTTP服务器就会发出一个客户端错误,通常是400 Bad Request。

5.状态码。

       下面是一些常见的状态码及其代表的含义:

  • 200 OK:请求成功。如果是POST操作表明已经对服务器产生了预期的影响。
  • 301 Moved Permanently:尽管路径合法,但该请求路径已经不是所请求资源目前的官方路径了。
  • 303 See Other:通过某个路径请求资源时,客户端可以通过使用GET方法对响应的消息的Location头中给出的URL进行请求,以获取响应结果,但是对该资源的后续请求仍然需要通过请求当前路径完成。
  • 304 Not Modified:不需要在响应中包含文档的内容,原因在于请求头指出了客户端已经在缓存中存储了所请求文档的最新版本。
  • 307 Temporary Redirect:无论客户端使用GET或POST方法发起了什么样的请求,都需要使用响应的Location头中给出的另外一个URL重新发送请求。
  • 400 Bad Request:请求不是一个合法的HTTP请求。
  • 403 Forbidd:客户端没有在请求中向服务器提供正确的密码、cookie或其他验证数据来证明客户端有访问服务器的权限。
  • 404 Not Found:路径没有一个已经存在的资源。
  • 405 Method Not Allowed:服务器能够识别方法和路径,但是该方法无法应用于该路径。
  • 500 Server Error:服务器希望完成请求,但是由于某些内部的错误,暂时无法请求。
  • 501 Not Implemented:服务器无法识别请求中给出的HTTP方法。
  • 502 Bad Gateway:请求的服务器是一个网关或者代理,它无法连接到真正为该请求路径提供响应的服务器。

你可能感兴趣的:(学习)