
Python 中继承 SimpleHTTPRequestHandler 自定义 HTTP 服务器时,若未调用 self.end_headers(),响应头将不会被实际发送,导致浏览器无法识别 Content-Type,从而以纯文本方式显示 HTML 内容。
python 中继承 `simplehttprequesthandler` 自定义 http 服务器时,若未调用 `self.end_headers()`,响应头将不会被实际发送,导致浏览器无法识别 `content-type`,从而以纯文本方式显示 html 内容。
在使用 http.server 模块构建自定义 HTTP 处理器时,一个常见但容易被忽略的关键点是:仅调用 send_header() 并不会真正将响应头写入网络流——必须显式调用 self.end_headers() 才能结束头部写入、分隔响应头与响应体,并触发底层缓冲区刷新。
回顾原始代码的问题所在:
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=UTF-8')
self.send_header('Content-Length', len(html_content)) # ❌ 错误:len() 返回 int,但 send_header 要求 str
self.wfile.write(html_content.encode('utf-8')) # ❌ 错误:在 end_headers() 前写入 body这里存在两个关键错误:
-
send_header('Content-Length', ...)的值必须是字符串(如'234'),传入整数会引发TypeError; -
最核心问题:缺少
self.end_headers()调用 —— 导致所有已设置的响应头(包括Content-Type)从未被写出,浏览器因此收不到任何响应头,只能依据默认行为(如text/plain)解析响应体,造成 HTML 源码被直接显示而非渲染。
✅ 正确做法如下:
立即学习“Python免费学习笔记(深入)”;
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)
self.send_header('Content-Type', 'text/html; charset=UTF-8')
self.send_header('Content-Length', str(len(html_content))) # ✅ 字符串化长度
self.end_headers() # ✅ 必须!分隔 headers 和 body
self.wfile.write(html_content.encode('utf-8')) # ✅ 此时 write 才安全
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)? 补充说明与最佳实践:
-
self.end_headers()不仅发送已设置的 Header,还会自动添加Date和Server等标准字段; - 若需设置多个自定义 Header(如
Cache-Control、X-Content-Type-Options),务必全部在end_headers()之前调用send_header(); -
Content-Length非强制,但显式设置有助于客户端准确解析响应边界;若省略,SimpleHTTPRequestHandler在end_headers()中可能自动补全(依赖 Python 版本),但显式声明更可靠; - 绑定地址建议明确指定为
"127.0.0.1",避免监听所有接口(""等价于0.0.0.0),防止本地服务意外暴露至局域网。
运行修正后的服务,在浏览器中访问 http://127.0.0.1:8098,即可看到正常渲染的 <h1>Hello, World!</h1> 页面,而非原始 HTML 文本。这印证了响应头已成功送达并被浏览器正确解析。



















