# 超文本传输协议

> 原文：[HTTP](https://www.textbook.ds100.org/ch/07/web_http.html)
> 
> 校验：[Kitty Du](https://github.com/miaoxiaozui2017)
> 
> 自豪地采用[谷歌翻译](https://translate.google.cn/)

```python
# HIDDEN
# Clear previously defined variables
%reset -f

# Set directory for data loading to work properly
import os
os.chdir(os.path.expanduser('~/notebooks/07'))

```

## Http[](#Http)
Http（AKA **H**yper**T**ext **T**transfer **P**rotocol）是一种 *请求-响应(request-response)* 协议，允许一台计算机通过 Internet 与另一台计算机对话。

## 请求和响应[](#Requests-and-Responses)

互联网允许计算机互相发送文本，但不会对文本包含的内容施加任何限制。HTTP 定义了一台计算机（客户端client）和另一台计算机（服务器server）之间的文本通信结构。在这个协议中，客户机向服务器提交一个 *请求*，是一个特殊格式的文本消息。服务器将送回一个*响应*文本到客户端。

命令行工具`curl`为我们提供了发送 HTTP 请求的简单方法。在下面的输出中，以`>`开头的行表示请求中发送的文本；其余的行是服务器的响应。

```bash
$ curl -v https://httpbin.org/html

```

```
> GET /html HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.55.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< Connection: keep-alive
< Server: meinheld/0.6.1
< Date: Wed, 11 Apr 2018 18:15:03 GMT
< 
<html>
  <body>
    <h1>Herman Melville - Moby-Dick</h1>
    <p>
      Availing himself of the mild...
    </p>
  </body>
</html>
```

运行上面的`curl`命令会使客户机的计算机构造一条如下所示的文本消息：

```
GET /html HTTP/1.1
Host: httpbin.org
User-Agent: curl/7.55.1
Accept: */*
{blank_line}
```

此消息遵循特定的格式：以`GET /html HTTP/1.1`开头，表示消息是对`/html`页的 HTTP`GET`请求。表单 HTTP 头后面的三行中的每一行，都是`curl`发送给服务器的可选信息。HTTP 头的格式为`{name}: {value}`。最后，消息结尾的空白行告诉服务器消息在三个头之后结束。注意，我们在上面的代码段中用`{blank_line}`标记了空白行；在实际的消息中`{blank_line}`用空白行替换。

然后，客户端的计算机使用 Internet 将此消息发送到`https://httpbin.org`Web 服务器。服务器处理请求，并发送以下响应：

```
HTTP/1.1 200 OK
Connection: keep-alive
Server: meinheld/0.6.1
Date: Wed, 11 Apr 2018 18:15:03 GMT
{blank_line}
```

响应的第一行说明请求已成功完成。下面的三行组成了 HTTP 响应头，这是服务器发送回客户机的可选信息。最后，消息结束时的空白行告诉客户端服务器已完成发送响应头，然后将发送响应体：

```
<html>
  <body>
    <h1>Herman Melville - Moby-Dick</h1>
    <p>
      Availing himself of the mild...
    </p>
  </body>
</html>
```

几乎每一个与互联网交互的应用程序都使用这个 HTTP 协议。例如，在您的 Web 浏览器中访问[https://httpbin.org/html](https://httpbin.org/html) 会发出与上面的`curl`命令相同的基本 HTTP 请求。您的浏览器没有像上面那样将响应显示为纯文本，而是识别出文本是一个 HTML 文档，并将相应地显示它。

实际上，我们不会以文本形式写出完整的 HTTP 请求。相反，我们使用像`curl`或 Python 库这样的工具来构造请求。

### Python中[](#In-Python)

Python **requests**库允许我们用 Python 发出 HTTP 请求。下面的代码发出的 HTTP 请求与运行`curl -v https://httpbin.org/html`相同。

```python
import requests

url = "https://httpbin.org/html"
response = requests.get(url)
response

```

```
<Response [200]>
```

### 请求[](#The-Request)

让我们仔细看看我们提出的请求。我们可以使用`response`对象访问原始请求；我们在下面显示请求的 HTTP 头：

```python
request = response.request
for key in request.headers: # The headers in the response are stored as a dictionary.
    print(f'{key}: {request.headers[key]}')

```

```
User-Agent: python-requests/2.12.4
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

```

每个 HTTP 请求都有一个类型。在本例中，我们使用了一个从服务器检索信息的`GET`请求。

```python
request.method

```

```
'GET'
```

### 响应[](#The-Response)

让我们检查一下从服务器收到的响应。首先，我们将打印响应的 HTTP 头。

```python
for key in response.headers:
    print(f'{key}: {response.headers[key]}')

```

```
Connection: keep-alive
Server: gunicorn/19.7.1
Date: Wed, 25 Apr 2018 18:32:51 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 3741
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0
Via: 1.1 vegur

```

HTTP 响应包含一个状态码，是一个特殊的数字，表示请求是成功还是失败。状态码`200`表示请求成功。

```python
response.status_code

```

```
200
```

最后，我们显示响应内容的前 100 个字符（整个响应内容太长，无法在这里很好地显示）。

```python
response.text[:100]

```

```
'<!DOCTYPE html>\n<html>\n  <head>\n  </head>\n  <body>\n      <h1>Herman Melville - Moby-Dick</h1>\n\n     '
```

## 请求类型[](#Types-of-Requests)

我们上面的请求是一个`GET`Http 请求。有多种 HTTP 请求类型；最重要的两种是`GET`和`POST`请求。

### GET 请求[](#GET-Requests)

`GET`请求用于从服务器检索信息。由于您每次在地址栏中输入 URL 时您的 Web 浏览器都会发出`GET`请求，`GET`请求是最常见的 HTTP 请求类型。

`curl`默认使用`GET`请求，因此运行`curl https://www.google.com/`会向`https://www.google.com/`发出`GET`请求。

### POST请求[](#POST-Request)

`POST`请求用于将信息从客户端发送到服务器。例如，一些网页包含供用户填写的表单，例如登录表单。单击“提交”按钮后，大多数 Web 浏览器都会发出一个`POST`请求，将表单数据发送到服务器进行处理。

让我们来看一个将`'sam'`作为参数`'name'`发送的`POST`请求的例子。这个可以通过在命令行上运行 **`curl -d 'name=sam' https://httpbin.org/post`** 来完成。

请注意，这次我们的请求有一个主体（用`POST`请求的参数填充），响应的内容与之前的`GET`响应不同。

与 HTTP 头类似，以`POST`请求发送的数据使用键值格式。在 Python 中，我们可以通过使用`requests.post`并将字典作为参数传入来发出`POST`请求。

```python
post_response = requests.post("https://httpbin.org/post",
                              data={'name': 'sam'})
post_response

```

```
<Response [200]>
```

服务器将用状态码响应，以表示`POST`请求是否成功完成。此外，服务器通常会发送一个响应主体来显示给客户机。

```python
post_response.status_code

```

```
200
```

```python
post_response.text

```

```
'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "name": "sam"\n  }, \n  "headers": {\n    "Accept": "*/*", \n    "Accept-Encoding": "gzip, deflate", \n    "Connection": "close", \n    "Content-Length": "8", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "httpbin.org", \n    "User-Agent": "python-requests/2.12.4"\n  }, \n  "json": null, \n  "origin": "136.152.143.72", \n  "url": "https://httpbin.org/post"\n}\n'
```

## 响应状态码类型[](#Types-of-Response-Status-Codes)

先前的 HTTP 响应的 HTTP 状态码为`200`。此状态码表示请求已成功完成。还有数百个其他的 HTTP 状态码。谢天谢地，它们被分为不同的类别，以便于记忆：

*   **100s**-信息：需要更多来自客户端或服务器的输入 _（例如 100 Continue(继续)、102 Processing(处理中)）_
*   **200S**-成功：客户端请求成功 _（例如 200 OK(成功)，202 Accepted(已接受)）_
*   **300s**-重定向：请求的 URL 位于其他位置；可能需要用户的进一步操作 _（例如，300 Multiple Choices(多个选项)，301 Moved Permanently(永久移动)）_
*   **400s**-客户端错误：客户端错误 _（例如 400 Bad Request(错误请求)，403 Forbidden(禁止)，404 Not Found(未找到)）_
*   **500s**-服务器错误：服务器端错误或服务器无法执行请求 _（例如，500 Internal Server Error(内部服务器错误)，503 Service Unavailable(服务不可用)）_

我们可以看看其中一些错误的例子。

```python
# This page doesn't exist, so we get a 404 page not found error
url = "https://www.youtube.com/404errorwow"
errorResponse = requests.get(url)
print(errorResponse)

```

```
<Response [404]>

```

```python
# This specific page results in a 500 server error
url = "https://httpstat.us/500"
serverResponse = requests.get(url)
print(serverResponse)

```

```
<Response [500]>

```

## 摘要[](#Summary)

我们介绍了 HTTP 协议，这是使用 Web 的应用程序的基本通信方法。尽管协议指定了一种特定的文本格式，但我们通常使用其他工具来为我们发出 HTTP 请求，例如命令行工具`curl`和 Python 库`requests`。
