
使用 http.server.SimpleHTTPRequestHandler 自定义服务器时,若未调用 self.end_headers(),响应头将不会被发送,导致浏览器无法识别 Content-Type,从而以纯文本形式显示 HTML 源码。
使用 `http.server.simplehttprequesthandler` 自定义服务器时,若未调用 `self.end_headers()`,响应头将不会被发送,导致浏览器无法识别 `content-type`,从而以纯文本形式显示 html 源码。
在 Python 的 http.server 模块中,SimpleHTTPRequestHandler 提供了构建轻量级 HTTP 服务器的基础能力,但其响应流程需严格遵循 HTTP 协议规范:响应状态行 → 响应头 → 空行(CRLF)→ 响应体。关键点在于:send_header() 仅将头部字段缓存到内部缓冲区,并不会实际写入网络流;必须显式调用 self.end_headers() 才会输出所有已设置的头部、插入分隔空行,并完成头部阶段。
在原始代码中,虽然设置了 'Content-Type' 和 'Content-Length',但遗漏了 self.end_headers(),导致浏览器收不到任何响应头(仅收到无头的 HTML 字节流),因此默认按 text/plain 解析并显示为源码。
✅ 正确做法如下:
import http.server
import socketserver
class CustomHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
html_content = "<html><body><h1>Hello, World!</h1></body></html>"
self.send_response(200) # 发送状态行:HTTP/1.1 200 OK
self.send_header('Content-Type', 'text/html; charset=UTF-8')
self.send_header('Content-Length', str(len(html_content))) # 注意:必须是字符串!
self.end_headers() # ✅ 关键:刷新头部并写入空行
self.wfile.write(html_content.encode('utf-8')) # 写入响应体
def main(port_no):
# 推荐显式绑定到 127.0.0.1(而非 ""),提升安全性与可调试性
with socketserver.TCPServer(("127.0.0.1", port_no), CustomHandler) as httpd:
print(f"Serving at http://127.0.0.1:{port_no}")
httpd.serve_forever()
if __name__ == '__main__':
main(8098)⚠️ 注意事项:
立即学习“前端免费学习笔记(深入)”;
-
send_header('Content-Length', ...)的值必须是字符串类型,传入整数会引发TypeError; -
end_headers()必须在所有send_header()调用之后、wfile.write()之前执行; - 若响应体为空(如 304 或 204),仍需调用
end_headers(),否则连接可能挂起; - 绑定地址建议使用
"127.0.0.1"而非""(即0.0.0.0),避免意外暴露本地服务至局域网; - 如需支持更多 MIME 类型(如 CSS、JS、JSON),可扩展
do_GET并动态设置对应Content-Type。
总结:end_headers() 是 HTTP 响应生成链中不可省略的“开关”,它标志着头部结束与正文开始。忽略它,再正确的 Content-Type 也形同虚设——浏览器永远看不到响应头。



















