通过一个 HTML 文档提供内容,并设置 Content-Type: text/html; charset=utf-8,在文档头部放置标题和描述,在正文中放置可读内容。本 Mac 操作指南会构建一个合成页面,并检查一个响应是否包含这三项内容。

此任务是准备一份浏览器可读的公共文档,先在本地预览,再将相同结构移植到发布系统中。示例仅包含关于纸张形状的虚构文字,不需要任何外部资源。

单个带类型的 HTTP 响应中应包含什么?

“带类型”意味着响应声明了其媒体类型。Content-Type 字段会告知接收方该表示的格式及预期处理方式。这里的格式是 HTML。它并不提供逐字段的应用程序架构。RFC 9110,第 8.3 节

HTTP/1.1 响应包含状态行、头字段、一个空行,以及可选的正文。因此,你可以在头部发送传输元数据,并在正文中放入完整文档,而无需单独发起元数据请求。RFC 9112,第 2.1 节

对于此发布任务,请使用以下放置指南。它将描述 HTTP 表示的信息与描述页面的信息区分开来。

信息 位置 示例
表示格式和编码 HTTP 头部 Content-Type: text/html; charset=utf-8
文档标题 HTML 头部 <title>纸张形状:圆形和正方形</title>
页面摘要 HTML 头部 <meta name="description" content="A short guide to arranging paper circles and squares.">
面向读者的内容 HTML 正文 标题、介绍和摆放说明

WHATWG 将 title 元素定义为文档的标题或名称,将 description 元数据值定义为对页面的描述。使用一个标题,description 声明最多一个。它们位于 HTML 文档内部,因此内容和描述性元数据会一同传送。HTML 标准:文档元数据

如何在 Mac 上构建可用的预览?

打开 Terminal 并检查可用命令:

python3 --version
curl --version

下面的程序需要 Python 3.7 或更高版本,且只使用其标准库。如果无法使用 python3,请按照官方 macOS 安装说明操作,然后重新打开 Terminal。Python 文档介绍了安装程序,以及如何在终端中调用 python3。在 macOS 上使用 Python

将下面的完整代码块粘贴到 Terminal 中,包括开头的命令和最后一行 PY。这会直接运行程序,不会创建或覆盖文件。检查页面时,请保持此终端窗口处于运行状态。

python3 - <<'PY'
from html import escape
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

TITLE = "Paper Shapes: Circle and Square"
SUMMARY = "A short guide to arranging paper circles and squares."
PAGE = f"""<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{escape(TITLE)}</title>
<meta name="description" content="{escape(SUMMARY, quote=True)}">
</head>
<body>
<main>
<h1>{escape(TITLE)}</h1>
<p>{escape(SUMMARY)}</p>
<h2>Try a simple arrangement</h2>
<p>Place one paper circle beside one paper square.</p>
<p>Switch their positions — then compare the two arrangements.</p>
</main>
</body>
</html>
""".encode("utf-8")

class Handler(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.1"

    def respond(self, include_body):
        if self.path != "/paper-shapes":
            self.send_error(404, "Page not found")
            return
        self.send_response(200)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        self.send_header("Content-Length", str(len(PAGE)))
        self.end_headers()
        if include_body:
            self.wfile.write(PAGE)

    def do_GET(self):
        self.respond(True)

    def do_HEAD(self):
        self.respond(False)

if __name__ == "__main__":
    with ThreadingHTTPServer(("127.0.0.1", 8000), Handler) as server:
        print("Preview: http://127.0.0.1:8000/paper-shapes", flush=True)
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            pass
PY

该处理程序使用 Python 文档所述的响应方法:send_response() 启动响应,send_header() 添加字段,end_headers() 则在写入正文字节之前结束头部部分。Python HTTP 服务器文档

示例特意只定义一次 TITLE 和 SUMMARY。这些值同时用于元数据和可见文本,使这个小文档更容易保持一致地修改。对于较长的页面,描述可以不同于开篇段落,同时仍准确概括同一主题。

页面会先进行编码,再计算长度。HTTP 将 Content-Length 定义为八位字节数,也就是字节数;如果按字符计数,就会导致本例中的 em dash 长度计算错误。RFC 9110,第 8.6 节

如何验证内容和元数据是否一同送达?

打开第二个 Terminal 窗口并运行此命令。它会发起普通文档请求,并显示响应头和内容:

curl -i --max-time 10 http://127.0.0.1:8000/paper-shapes

-i 选项会将响应头与正文一同输出。时间限制会将传输限制在十秒内。这些选项见于 curl 命令行手册。

按顺序检查输出:

  1. 状态行应显示 200 OK。
  2. 单个 Content-Type 字段应声明 text/html; charset=utf-8。
  3. 头部部分后的空行之后,HTML 中应包含标题和描述。
  4. 同一正文中还应包含纸张形状的说明。
  5. 解码后的文本中应正确显示 em dash。

接下来,在 Safari 地址栏中输入 http://127.0.0.1:8000/paper-shapes。可见页面应显示其标题、摘要和说明。description 声明属于元数据;应通过检查返回的标记来确认它存在,而不是根据页面外观推断。

你还可以检查仅返回头部的路径:

curl -I --max-time 10 http://127.0.0.1:8000/paper-shapes

这会发送 HEAD,因此无法验证正文是否包含标题或描述。HEAD 响应会省略内容,同时描述相应的表示;请使用前面的 GET 检查来查看实际文档。RFC 9110,第 8.2 节

如果预览无法运行,请根据症状选择下一步操作:

症状 下一步操作
启动时提示地址已被占用 在程序中将 8000 改为 8001,重新运行程序,并在每条预览命令中使用 8001。
请求提示连接失败 检查第一个终端是否仍显示预览正在运行,并确认端口一致。
响应为 404 请准确使用 /paper-shapes;此示例不接受尾部斜杠或查询字符串。
浏览器仍显示旧版本 使用 Control-C 停止程序,重新运行修改后的代码块,然后重新加载页面。
标题显示正确,但元数据缺失 检查 GET 输出,并确认声明位于文档头部内。

Google Search 可以从此响应中使用什么?

描述准确的标题、准确的描述以及有用的可见文本,都是 Google 在展示页面时记录在案的输入。Google 将 title 元素、主要视觉标题、标题元素及其他来源列为自动生成搜索结果标题链接时的输入。请让这些信息与文档主题保持一致。影响搜索结果中的标题链接

Google 主要根据页面内容生成摘要,有时也会使用 meta description;当它能更准确地描述页面时,Google 可能会选择它。不同搜索可能会产生不同摘要。应将描述视为有用的摘要,而不是固定的搜索结果说明文字。控制搜索结果中的摘要

在这个合成示例中,描述承诺提供简短的摆放指南,而正文也确实提供了该指南。替换示例文本时,请明确检查两者的关系:只阅读描述的人也应能准确预期页面内容。

添加自定义元数据名称并不意味着它们受到支持。Google 表示,它会忽略不支持的 meta 标签。对于面向搜索的元数据,请使用其文档说明的字段;为自己的应用程序发明的字段则需要另行定义使用方。Google 支持的 meta 标签和属性

如何将预览转变为公开发布模式?

本操作指南中的本地地址是桌面预览,并非已发布页面。Python 也说明,http.server 不建议用于生产环境。请将 HTML 结构和响应要求移植到发布系统中,而不要将此演示用作公共托管服务。Python HTTP 服务器文档

如果你使用内容管理系统,请查找其中有文档说明的页面标题和 meta description 控件。Google 指出,CMS 可能会提供搜索设置,而不是直接编辑 HTML 的功能。将这些控件映射到此处展示的字段,然后检查生成的文档响应。Google 关于添加 meta description 的指南

HTTP 确实支持多部分表示,但那是另一种打包方式。对于此浏览器可读文档任务,现有的 HTML 结构已能让内容和文档元数据包含在同一个表示中。选择多部分会增加接收方处理要求,而本操作指南并不需要这种要求。RFC 9110,第 8.3.3 节

完成检查很具体:一次成功的文档请求应返回正确的媒体类型、完整的 HTML 正文、准确的标题和描述,以及读者需要的文本。将这项检查应用于最终的公开响应和本地预览,确保发布系统的输出与准备好的文档一致。

来源