使用标准库发送网络请求

PythonBeginner
立即练习

简介

在运维工作中,检查 Web 服务是否可用是一项常见任务。虽然 requests 等第三方库很受欢迎,但在受限环境中,有时只能依赖 Python 标准库。

在本实验中,你将使用 Python 标准库中的 urllib 模块创建一个简单的网络连接检查器。这个过程说明,即使不添加额外依赖,也可以构建实用的运维工具。

完成本实验后,你将了解如何:

  • 导入 urllib.request 模块。
  • 定义用于检查 URL 的函数。
  • 获取 HTTP 状态码,例如 200 OK。
  • 处理服务器错误或主机无法访问等异常。
  • 显示易于理解的状态消息。

导入模块

在本步骤中,先创建 Python 脚本并导入所需模块。urllib.request 是 Python 内置的 URL 打开工具。你可以把它理解为一个由代码控制的 Web 浏览器,例如 Chrome 或 Firefox,而不需要使用鼠标。它可以让脚本从互联网获取数据。

这对运维工作很有用,因为许多系统会提供基于 HTTP 的 API 或健康检查端点。即使团队之后采用第三方库,理解标准库工具也能帮助你更清楚地掌握底层的请求—响应模型。

首先确认当前位于正确的目录。打开终端并进入项目目录:

cd ~/project

现在,使用 nano 文本编辑器(或你喜欢的其他编辑器)创建名为 connectivity_check.py 的 Python 文件:

nano connectivity_check.py

在 Python 中,使用库之前必须先导入它。在文件顶部添加以下内容。这里导入 urllib.request 来处理请求,导入 urllib.error 来处理后续可能出现的错误。

import urllib.request
import urllib.error

按 Ctrl+O,再按 Enter 保存文件,然后按 Ctrl+X 退出 nano。

你可以使用 cat 命令验证文件内容:

cat connectivity_check.py

定义函数

现在已经准备好导入模块,接下来需要组织代码。将逻辑封装在函数中是一种良好实践,这样代码更易于复用和测试。

函数在运维脚本中特别有用,因为同一个操作通常需要针对多个目标执行。将网络检查封装到函数后,你可以为不同的 URL 调用该函数,而不必重复编写代码。

在本步骤中,定义名为 check_url 的函数,并让它接收一个 URL 字符串作为参数。

再次打开 connectivity_check.py 文件:

nano connectivity_check.py

将以下函数定义添加到导入语句下方。现在先添加 pass 语句。在 Python 中,pass 是表示「不执行任何操作」的占位语句。下一步会补充具体逻辑。

import urllib.request
import urllib.error

def check_url(url):
    print(f"Checking connectivity for: {url}")
    ## Logic will go here
    pass

保存并退出编辑器(Ctrl+O、Enter、Ctrl+X)。

这个结构为后续代码搭建了基础。check_url 函数接收一个名为 url 的参数,该参数表示要测试的网站地址,例如 "https://www.google.com"。

发送请求

在本步骤中,实现发送请求并获取 HTTP 状态码的核心逻辑。HTTP 状态码 200 通常表示「OK」,也就是请求成功。

从整体上看,HTTP 请求是客户端与服务器之间的一次对话。你的脚本充当客户端,向 URL 发送请求,等待服务器响应,然后检查状态码等元数据,再决定下一步操作。

我们将使用 urllib.request.urlopen() 打开 URL。该函数会返回一个响应对象,响应对象提供 .getcode() 方法,用于获取状态码。

打开 connectivity_check.py:

nano connectivity_check.py

将 check_url 函数更新为以下内容。注意,这里设置了 5 秒超时,防止服务器没有响应时脚本一直等待。

import urllib.request
import urllib.error

def check_url(url):
    print(f"Checking connectivity for: {url}")

    ## Open the URL with a 5-second timeout
    response = urllib.request.urlopen(url, timeout=5)

    ## Get the status code
    status_code = response.getcode()

    print(f"Status Code: {status_code}")

注意:在此阶段,如果 URL 无效或服务器已停止运行,脚本会崩溃,因为我们还没有添加错误处理。下一步将解决这个问题。

保存并退出编辑器。

处理错误

网络编程具有不可预测性。服务器可能停止运行,DNS 查询可能失败,互联网连接也可能中断。如果 urlopen 执行失败,就会引发异常。为了让脚本更加健壮,必须使用 try...except 代码块处理这些异常。

在实际监控中,区分不同的故障类型非常重要。服务器返回 500,表示你已经连接到服务器,并且服务器报告了内部问题。而 URLError 通常表示请求根本没有到达可用的 HTTP 端点。优秀的运维人员会将它们视为不同类型的事件。

我们将处理以下两种具体错误:

  • urllib.error.HTTPError:服务器返回了响应,但状态码表示错误,例如 404 Not Found 或 500 Server Error。
  • urllib.error.URLError:根本无法访问服务器,例如没有互联网连接或域名错误。

你可以把 try...except 代码块理解为安全网。如果发生问题,例如互联网连接中断,代码不会直接崩溃,而是进入 except 代码块,在那里捕获错误并显示有帮助的信息。

打开 connectivity_check.py:

nano connectivity_check.py

修改函数,将请求逻辑放入 try 代码块中:

import urllib.request
import urllib.error

def check_url(url):
    print(f"Checking connectivity for: {url}")

    try:
        ## Attempt to open the URL
        response = urllib.request.urlopen(url, timeout=5)
        status_code = response.getcode()
        print(f"Success! Status Code: {status_code}")

    except urllib.error.HTTPError as e:
        ## Server responded with an error (e.g., 404, 500)
        print(f"HTTP Error: {e.code}")

    except urllib.error.URLError as e:
        ## Failed to reach the server
        print(f"URL Error: {e.reason}")

代码会先尝试执行 try 代码块中的语句。如果发生错误,Python 会停止执行 try 代码块,并跳转到匹配的 except 代码块。

保存并退出编辑器。

测试脚本

在最后一个步骤中,添加一个调用函数的主代码块,使脚本可以直接执行。这样就能从终端直接运行脚本。

if __name__ == "__main__": 是 Python 中的惯用模式,用于区分可复用的函数和直接执行脚本时应运行的代码。这个小型设计可以方便后续复用,因为其他脚本导入 check_url 时,不会自动执行测试调用。

我们将使用一个已知可用的 URL(例如 https://www.example.com)进行测试。你也可以测试一个虚构的 URL,观察错误处理的效果。

打开 connectivity_check.py:

nano connectivity_check.py

将以下代码添加到文件末尾:

if __name__ == "__main__":
    ## Test with a valid URL
    target_url = "https://www.example.com"
    check_url(target_url)

    print("-" * 20)

    ## Test with an invalid URL to see error handling
    invalid_url = "https://www.this-domain-does-not-exist-12345.com"
    check_url(invalid_url)

if __name__ == "__main__": 代码块确保其中的代码只会在直接执行脚本时运行,而不会在其他脚本将该文件作为模块导入时运行。

保存并退出编辑器。

现在运行脚本,查看结果:

python3 connectivity_check.py

你应该会看到类似以下内容的输出:

Checking connectivity for: https://www.example.com
Success! Status Code: 200
--------------------
Checking connectivity for: https://www.this-domain-does-not-exist-12345.com
URL Error: [Errno -2] Name or service not known

(注意:无效 URL 的具体错误消息可能会因网络环境不同而略有差异。)

总结

在本实验中,你已经成功使用 Python 标准库创建了一个网络连接检查器。你学习了如何:

  • 导入模块:使用 urllib.request 和 urllib.error。
  • 发送 HTTP 请求:使用 urlopen 连接 Web 服务器。
  • 处理响应:获取 HTTP 状态码,以验证服务是否可用。
  • 管理错误:使用 try...except 代码块处理 HTTPError 和 URLError,让脚本能够应对网络故障。

这项技能是创建监控脚本、健康检查工具和简单 Web 抓取器的基础,尤其适用于无法安装外部依赖的环境。