静态 web 服务器编程

静态 web 服务器编程

HTTP 协议概念

HTTP 协议,全称是 HyperText Transfer Protocol(超文本传输协议),是一种用于从 Web 服务器传输网页数据到浏览器客户端的网络通信协议。它是整个万维网(WWW)的基础,定义了客户端(比如浏览器)和服务器之间如何请求和响应数据。

一、HTTP 协议的基本特点

特点说明
应用层协议属于 OSI 七层模型中的应用层,用于 Web 通信
基于请求响应客户端发出请求(Request),服务器返回响应(Response)
无状态协议每次请求之间彼此独立,服务器不会记住之前的交互
基于文本报文内容(请求和响应)通常是纯文本,便于人类阅读和调试
默认端口默认使用端口号 80,HTTPS(加密的 HTTP)使用 443

二、HTTP 的基本通信过程

  1. 客户端发起请求(比如访问 https://example.com);
  2. DNS 解析域名,获取服务器 IP;
  3. 客户端向服务器发送 HTTP 请求报文
  4. 服务器处理请求,返回 HTTP 响应报文(包括网页 HTML、图片、CSS、JS 等);
  5. 客户端(如浏览器)解析并展示网页内容

三、HTTP 请求报文结构

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
  • 请求方法:GET、POST、PUT、DELETE 等;
  • 路径:/index.html;
  • 协议版本:HTTP/1.1;
  • 请求头:告知服务器客户端的能力和偏好;
  • 请求体(可选):如 POST 请求时携带的表单数据。

四、HTTP 响应报文结构

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234

<html>
  <body>Hello, World!</body>
</html>
  • 状态行:HTTP 版本 + 状态码(如 200 OK、404 Not Found);
  • 响应头:描述响应体的内容类型、长度、缓存控制等;
  • 响应体:实际的数据,如网页内容。

五、常见 HTTP 状态码

状态码含义
200请求成功
301永久重定向
302临时重定向
400请求有误
401未授权(需登录)
403禁止访问
404页面未找到
500服务器内部错误

六、HTTP 的演变(简要)

版本特点
HTTP/0.9最早期版本,只支持 GET 请求
HTTP/1.0增加了请求头和响应头
HTTP/1.1引入持久连接、管道化、缓存控制等优化
HTTP/2二进制格式、高效传输、多路复用、更快加载速度
HTTP/3基于 QUIC 协议,减少延迟,适应现代网络环境

客户端和服务器交互的 HTTP 通信流程

静态 web 服务器编程

什么是 URL

URL(Uniform Resource Locator)统一资源定位符,是互联网上用于标识和定位资源(如网页、图片、视频、API)的地址。
简单来说,URL 就是你在浏览器地址栏输入的地址,例如:

https://www.example.com:443/path/page.html?user=jack&id=123#top

URL 的组成部分

协议://用户名:密码@主机名:端口/路径?查询参数#片段标识
部分示例说明
协议https指定访问方式,如 http, https, ftp
用户名:密码user:pass@(可选)用于需要认证的 URL,铭文展示,现代浏览器多已禁用此功能
主机名www.example.com域名或 IP 地址
端口号:443(可选)默认为 80(HTTP)或 443(HTTPS)
路径/path/page.html指定访问资源的路径
查询参数?user=jack&id=123使用 ? 开始,多个参数用 & 分隔
片段标识#top页面内锚点,不会发送给服务器,仅供浏览器定位

查询参数格式详解

key1=value1&key2=value2&key3=value3
  • 每个参数由 键值对(key=value) 构成;
  • 多个参数之间用 & 分隔;
  • 中文或特殊字符需要进行 URL 编码(如空格 → %20);

Chrome 前端调试工具介绍

打开方式:快捷键:F12Ctrl + Shift + I(Mac: Cmd + Option + I

主要功能面板介绍

面板名主要作用
Elements查看/修改 HTML 和 CSS 结构、调试样式
Console打印日志、查看报错、执行 JS 代码
Sources查看页面加载的所有文件,支持设置断点调试 JS
Network查看所有网络请求(接口、图片、CSS 等),可分析加载时间等
Application管理 Cookie、本地存储、缓存等
Performance分析网页性能瓶颈、帧率等
Lighthouse一键生成网页性能报告
Device Mode切换为手机模拟视图,调试响应式布局

常用场景示例

1. 修改网页样式(Elements)

  • 选中元素 → 修改 class、style
  • 实时预览改动,不影响原网页文件

2. 查看接口数据(Network)

  • 切换到 Network 面板
  • 刷新页面,查看每个请求的 URL、状态码、响应内容
  • 选中某一项 → 查看 Headers、Response、Preview 等

3. 调试 JavaScript(Console & Sources)

  • Console 中输入 JS 代码直接运行
  • Sources 中设置断点、逐行执行、查看变量

4. 查看本地存储数据(Application)

  • 查看或删除 localStorage、sessionStorage、cookie

Network(网络)面板

展示了 HTTP 请求和响应的详细信息,帮助开发者调试网络通信。以下是 HTTP 返回时 Network 面板中常见的主要内容分类:

Headers(请求与响应头)

  • General(常规)
    • Request URL:请求地址
    • Request Method:请求方法(GET、POST、PUT 等)
    • Status Code:HTTP 状态码和提示
    • Remote Address:远程服务器 IP 和端口
    • Referrer Policy:引用策略
  • Response Headers(响应头)
    • Content-Type:响应内容类型,如 application/json
    • Content-Length:响应体长度
    • Cache-Control:缓存策略
    • Set-Cookie:设置的 Cookie 信息
    • Server:服务器类型(如 nginx)
  • Request Headers(请求头)
    • Host:目标服务器域名
    • User-Agent:浏览器信息
    • Accept:可接受的响应类型
    • Authorization:认证信息(如 Bearer Token)
    • Cookie:发送的 Cookie

Preview(预览)

  • 渲染后的响应内容预览,适用于 JSON、HTML、图像等类型
静态 web 服务器编程

Response(原始响应内容)

  • 响应体的原始数据(如 JSON 字符串、HTML 文本)
静态 web 服务器编程

Initiator(触发器)

  • 展示是哪段代码或资源触发了这个请求(通常是 JS)
静态 web 服务器编程

Timing(时间)

  • 展示详细的请求时间线,包括:
    • Stalled(阻塞时间)
    • DNS Lookup
    • Initial Connection
    • SSL
    • Request Sent
    • Waiting (TTFB: 首字节时间)
    • Content Download
静态 web 服务器编程

Cookies

  • 显示请求中发送的 Cookie 和响应中设置的 Cookie
静态 web 服务器编程

HTTP 请求报文

GET 方式的请求报文

例如:

GET /search?keyword=chatgpt&page=1 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Connection: keep-alive
Referer: https://www.example.com/

请求行

GET /search?keyword=chatgpt&page=1 HTTP/1.1
请求行字段含义
GET请求方法
/search?...路径 + 查询参数
HTTP/1.1协议版本

请求头

Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7
Accept: text/html,application/xhtml+xml,application/xml;q=0.9
Connection: keep-alive
Referer: https://www.example.com/

这些是浏览器自动添加的,告诉服务器:

  • 谁发的请求(User-Agent)
  • 请求了什么类型的数据(Accept)
  • 连接是否复用(Connection)
  • 来源页是哪个(Referer)

请求体

GET 方法 没有请求体。所有参数都放在 URL 里。

POST 方式的请求报文

例如:

POST /login HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Connection: keep-alive

username=admin&password=123456

请求行

POST /login HTTP/1.1
字段含义
POST请求方法
/login请求路径
HTTP/1.1协议版本

请求头

Host: www.example.com
User-Agent: Mozilla/5.0 ...
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
Connection: keep-alive

说明了:

  • 要发送的数据是表单格式(Content-Type)
  • 内容长度为 29 字节(Content-Length)

请求体

username=admin&password=123456

表单数据真实内容,这才是服务器要接收和处理的用户提交信息。

GET/POST 总结对比

项目GETPOST
请求体❌ 没有✅ 有
参数位置URL 后的 ?query请求体中
数据可见性暴露在地址栏不显示在地址栏
安全性相对较低(可被缓存/记录)相对更高(适合敏感数据)
长度限制有限制(URL 长度)理论无限(服务器配置限制)
常见用途查询、获取数据提交数据,如表单、上传

HTTP 响应报文

静态 web 服务器编程

举个例子:完整响应报文示例(200 OK)

--- 状态行(Status Line)   ---
HTTP/1.1 200 OK
--- 响应头(Response Headers)   ---
Date: Sun, 08 Jun 2025 11:30:00 GMT
Content-Type: application/json
Content-Length: 37
Server: nginx/1.18.0
Set-Cookie: sessionid=abc123; Path=/; HttpOnly
--- 空行 ---
--- 响应体(Response Body) ---
{
  "status": "success",
  "data": "hello"
}

状态行(Status Line)

格式如下:

<HTTP版本> <状态码> <状态短语>

响应头(Headers)

用于说明响应的服务器信息、内容类型、缓存策略等。

常见响应头如下:

响应头说明
Content-Type响应体内容的类型,如 text/htmlapplication/json
Content-Length响应体的字节长度
Server服务器软件信息,如 nginx/1.18.0
Date响应发送的时间
Set-Cookie服务端设置 Cookie
Cache-Control是否缓存、缓存时长等
Content-Encoding内容压缩方式,如 gzipbr
Access-Control-Allow-OriginCORS 跨域控制头
Location重定向地址(3xx 响应时出现)
ETag响应资源的唯一标识,用于缓存比较

空行

请求头与响应体之间用一个空行(\r\n)隔开,表示 响应头结束,响应体开始

响应体(Body)

  • 客户端真正接收到的内容,比如 HTML 页面、JSON 数据、图片、文件等。
  • 不同的 Content-Type 会导致响应体格式不同。

示例:

Content-Type: application/json → 响应体是 JSON:

{"code":200,"message":"登录成功"}

Content-Type: text/html → 响应体是网页 HTML:

<html><body><h1>Hello</h1></body></html>

搭建 Python 自带的 web 静态服务器

静态 Web 服务器是什么?

静态 Web 服务器专门用来存储并直接“原样”返回静态资源(如 HTML 文件、图片、CSS、JS 等)的服务器。它不处理业务逻辑、不操作数据库,仅仅负责把文件送出去。

什么是“静态资源”?

静态资源 = 内容固定、服务器不需要计算就能返回的文件:

类型示例
HTML 页面index.htmlabout.html
图片.jpg.png.svg
样式表.css
JavaScript 脚本.js
文档文件.pdf.txt

静态 Web 服务器的作用

当你访问网页(如 https://example.com/index.html)时,静态服务器会:

  1. 根据 URL 找到对应的文件
  2. 加载它
  3. 原样发送给浏览器

不做任何修改、不接触数据库、不执行脚本。

常见静态 Web 服务器软件

软件简介
Nginx高性能 Web 服务器,静态文件处理效率极高
Apache HTTP Server功能丰富,也可以做静态资源服务
Node.js + Express + express.static用于前端开发时快速启动本地静态服务
Python 内置 HTTP Server用于调试,非常轻量
Vite / Webpack Dev Server前端开发中的临时本地静态服务器
GitHub Pages / Vercel / Netlify提供免费静态网站托管服务(CI/CD 支持)

Python 快速启动静态服务器

假设你有一个包含 index.html(内容为 hello web) 的文件夹 site/

cd site/
python3 -m http.server 8000

访问:http://localhost:8000/ → 就能访问你的静态网站

静态 web 服务器编程

原始 TCP Socket 手写最简版的静态 Web 服务器

实现思路:

  1. socket 模块创建 TCP 服务端;
  2. 监听端口,等待浏览器发来 HTTP request请求;
  3. 读取并解析 HTTP request请求;
  4. 根据请求的路径查找对应的文件并返回;
  5. 按照 HTTP 协议格式拼接 response 返回响应内容。

完整代码:

server_socket.py

import socket
import os

HOST = '127.0.0.1'
PORT = 8080
STATIC_DIR = 'static'  # 静态资源目录

def get_content_type(file_path):
    if file_path.endswith('.html'):
        return 'text/html'
    elif file_path.endswith('.css'):
        return 'text/css'
    elif file_path.endswith('.js'):
        return 'application/javascript'
    elif file_path.endswith('.png'):
        return 'image/png'
    elif file_path.endswith('.jpg') or file_path.endswith('.jpeg'):
        return 'image/jpeg'
    elif file_path.endswith('.ico'):
        return 'image/x-icon'
    else:
        return 'text/plain'

def handle_request(client_socket):
    try:
        request = client_socket.recv(1024).decode('utf-8')
        if not request:
            print("没有收到请求,关闭连接")
            return  # 提前返回,但 socket 仍会在 finally 中被关闭。

        print('📥 收到请求:')
        print(request)

        # 提取请求路径
        path_line = request.splitlines()[0]
        method, path, _ = path_line.split()
        if path == '/':
            path = '/index.html'
        
        file_path = os.path.join(STATIC_DIR, path.lstrip('/'))
        
        # 构建响应
        if os.path.isfile(file_path):
            with open(file_path, 'rb') as f:
                body = f.read()
            content_type = get_content_type(file_path)
            response = (
                'HTTP/1.1 200 OK\r\n'
                f'Content-Type: {content_type}; charset=utf-8\r\n'
                f'Content-Length: {len(body)}\r\n'
                '\r\n'
            ).encode('utf-8') + body
        else:
            body = b"<h1>404 Not Found</h1>"
            response = (
                'HTTP/1.1 404 Not Found\r\n'
                'Content-Type: text/html; charset=utf-8\r\n'
                f'Content-Length: {len(body)}\r\n'
                '\r\n'
            ).encode('utf-8') + body

        client_socket.sendall(response)

    except Exception as e:
        print(f"处理请求时发生错误: {e}")

    finally:
        client_socket.close()  # 确保客户端套接字在最后始终关闭


def start_server():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.bind((HOST, PORT))
        server.listen(5)
        print(f"🌐 Server is running at http://{HOST}:{PORT}/")

        while True:
            client_socket, addr = server.accept()
            handle_request(client_socket)

if __name__ == '__main__':
    start_server()

使用说明

  • 创建 static/ 文件夹;
  • 放入一个简单的 index.html(例如):
<!DOCTYPE html>
<html><body><h1>Hello Socket!</h1></body></html>
  • 运行服务器

python3 server_socket.py

  • 打开浏览器访问:
http://127.0.0.1:8080/

request:

静态 web 服务器编程

reponse headers:

静态 web 服务器编程

response body

静态 web 服务器编程

全代码详解

import socket
import os

# 服务监听地址和端口
HOST = '127.0.0.1'
PORT = 8080

# 存放网站静态资源的文件夹
STATIC_DIR = 'static'

函数:get_content_type(file_path)

这个函数是根据文件后缀判断 MIME 类型,用于构造响应头中的 Content-Type

def get_content_type(file_path):
    if file_path.endswith('.html'):
        return 'text/html'
    elif file_path.endswith('.css'):
        return 'text/css'
    elif file_path.endswith('.js'):
        return 'application/javascript'
    elif file_path.endswith('.png'):
        return 'image/png'
    elif file_path.endswith('.jpg') or file_path.endswith('.jpeg'):
        return 'image/jpeg'
    elif file_path.endswith('.ico'):
        return 'image/x-icon'
    else:
        return 'text/plain'  # 默认类型

函数:handle_request(client_socket)

这个函数用来处理客户端的一次 HTTP 请求。

def handle_request(client_socket):
    try:
        request = client_socket.recv(1024).decode('utf-8')
        if not request:
            print("没有收到请求,关闭连接")
            return  # 提前返回,但 socket 仍会在 finally 中被关闭。

        print('📥 收到请求:')
        print(request)

示例请求报文(GET):

GET /index.html HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 ...
Accept: text/html,...

解析请求行

    path_line = request.splitlines()[0]  # 只取第一行(请求行)
    method, path, _ = path_line.split()  # 拆分 GET /index.html HTTP/1.1
    if path == '/':
        path = '/index.html'  # 默认首页

文件路径转换

    file_path = os.path.join(STATIC_DIR, path.lstrip('/'))  # 构造完整文件路径

构建响应报文(重点!)

HTTP 响应由三部分构成:

响应行(Status Line)
响应头(Response Headers)
空行(\r\n)
响应体(Body)

如果文件存在(200 OK):

    if os.path.isfile(file_path):
        with open(file_path, 'rb') as f:
            body = f.read()  # 读取二进制文件内容作为响应体
        content_type = get_content_type(file_path)

        # 构造响应行 + 响应头
        response = (
            'HTTP/1.1 200 OK\r\n'                                 # 状态行
            f'Content-Type: {content_type}; charset=utf-8\r\n'   # 响应头
            f'Content-Length: {len(body)}\r\n'                    # 响应头
            '\r\n'                                                # 空行,后面开始是 body
        ).encode('utf-8') + body                                  # 拼接:响应头 + 响应体(二进制)

response 是拼接好的完整响应报文!

如果文件不存在(404 Not Found):

    else:
        body = b"<h1>404 Not Found</h1>"  # 返回的内容
        response = (
            'HTTP/1.1 404 Not Found\r\n'                          # 状态行
            'Content-Type: text/html; charset=utf-8\r\n'         # 响应头
            f'Content-Length: {len(body)}\r\n'                   # 响应头
            '\r\n'                                                # 空行
        ).encode('utf-8') + body                                  # 拼接响应头+体

发送响应并关闭连接

        client_socket.sendall(response)

    except Exception as e:
        print(f"处理请求时发生错误: {e}")

    finally:
        client_socket.close()  # 确保客户端套接字在最后始终关闭

函数:start_server()

这是整个 Web 服务的入口。

def start_server():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.bind((HOST, PORT))     # 绑定地址端口
        server.listen(5)              # 开始监听,最多 5 个等待连接
        print(f"🌐 Server is running at http://{HOST}:{PORT}/")

        while True:
            client_socket, addr = server.accept()  # 接收一个连接
            handle_request(client_socket)          # 交给处理函数

总结:响应报文构造位置

部分构造位置
响应行(如 HTTP/1.1 200 OKresponse = (...) 开头处的第一行
响应头(如 Content-Type, Content-Length.encode('utf-8') 前用字符串拼接
响应体(HTML / 图片 / CSS)+ body 拼接进去,必须是二进制
完整响应报文response = encode(响应行 + 响应头 + 空行) + body
发送client_socket.sendall(response)

使用线程实现多任务

import socket
import os
import threading

HOST = '127.0.0.1'
PORT = 8080
STATIC_DIR = 'static'  # 静态资源目录


def get_content_type(file_path):
    if file_path.endswith('.html'):
        return 'text/html'
    elif file_path.endswith('.css'):
        return 'text/css'
    elif file_path.endswith('.js'):
        return 'application/javascript'
    elif file_path.endswith('.png'):
        return 'image/png'
    elif file_path.endswith('.jpg') or file_path.endswith('.jpeg'):
        return 'image/jpeg'
    elif file_path.endswith('.ico'):
        return 'image/x-icon'
    else:
        return 'text/plain'


def handle_request(client_socket):
    try:
        request = client_socket.recv(1024).decode('utf-8')
        if not request:
            print("没有收到请求,关闭连接")
            return  # 提前返回,但 socket 仍会在 finally 中被关闭。

        print('📥 收到请求:')
        print(request)

        # 提取请求路径
        path_line = request.splitlines()[0]
        method, path, _ = path_line.split()
        if path == '/':
            path = '/index.html'

        file_path = os.path.join(STATIC_DIR, path.lstrip('/'))

        # 构建响应
        if os.path.isfile(file_path):
            with open(file_path, 'rb') as f:
                body = f.read()
            content_type = get_content_type(file_path)
            response = (
                'HTTP/1.1 200 OK\r\n'
                f'Content-Type: {content_type}; charset=utf-8\r\n'
                f'Content-Length: {len(body)}\r\n'
                '\r\n'
            ).encode('utf-8') + body
        else:
            body = b"<h1>404 Not Found</h1>"
            response = (
                'HTTP/1.1 404 Not Found\r\n'
                'Content-Type: text/html; charset=utf-8\r\n'
                f'Content-Length: {len(body)}\r\n'
                '\r\n'
            ).encode('utf-8') + body

        client_socket.sendall(response)

    except Exception as e:
        print(f"处理请求时发生错误: {e}")

    finally:
        client_socket.close()  # 确保客户端套接字在最后始终关闭


def start_server():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind((HOST, PORT))
        server.listen(5)
        print(f"🌐 Server is running at http://{HOST}:{PORT}/")

        while True:
            client_socket, addr = server.accept()
            print(f"👤 连接来自: {addr}")
            # 创建一个新线程来处理请求
            thread = threading.Thread(target=handle_request, args=(client_socket,))
            thread.start()  # 启动线程


if __name__ == '__main__':
    start_server()

代码优化说明

  1. 引入多线程支持:
    • 在 start_server 函数中,当有新连接接受时,创建一个新的 threading.Thread 实例来处理该连接。
    • 通过 args=(client_socket,) 将当前的 client_socket 传递给 handle_request 函数。
  2. 线程启动:
    • 使用 thread.start() 方法来启动线程,这样每个客户端的请求都会在自己的线程中处理。

面向对象写法

为什么改为面向对象

  • 结构更清晰:把功能封装进类中,每个类职责明确。
  • 更容易扩展:比如后续想支持 POST 方法、日志模块、安全认证、模板引擎等。
  • 更方便测试与复用:每个方法可以单独测试,不需要跑整个服务器。
  • 面向对象的封装和继承更适合大型项目开发。
import socket
import os
import threading

class SimpleHTTPServer:
    def __init__(self, host='127.0.0.1', port=8080, static_dir='static'):
        self.host = host
        self.port = port
        self.static_dir = static_dir

    def get_content_type(self, file_path):
        if file_path.endswith('.html'):
            return 'text/html'
        elif file_path.endswith('.css'):
            return 'text/css'
        elif file_path.endswith('.js'):
            return 'application/javascript'
        elif file_path.endswith('.png'):
            return 'image/png'
        elif file_path.endswith('.jpg') or file_path.endswith('.jpeg'):
            return 'image/jpeg'
        elif file_path.endswith('.ico'):
            return 'image/x-icon'
        else:
            return 'text/plain'

    def handle_request(self, client_socket):
        try:
            request = client_socket.recv(1024).decode('utf-8')
            if not request:
                print("没有收到请求,关闭连接")
                return

            print('📥 收到请求:')
            print(request)

            path_line = request.splitlines()[0]
            method, path, _ = path_line.split()

            if path == '/':
                path = '/index.html'

            file_path = os.path.join(self.static_dir, path.lstrip('/'))

            if os.path.isfile(file_path):
                with open(file_path, 'rb') as f:
                    body = f.read()
                content_type = self.get_content_type(file_path)
                response = (
                    'HTTP/1.1 200 OK\r\n'
                    f'Content-Type: {content_type}; charset=utf-8\r\n'
                    f'Content-Length: {len(body)}\r\n'
                    '\r\n'
                ).encode('utf-8') + body
            else:
                body = b"<h1>404 Not Found</h1>"
                response = (
                    'HTTP/1.1 404 Not Found\r\n'
                    'Content-Type: text/html; charset=utf-8\r\n'
                    f'Content-Length: {len(body)}\r\n'
                    '\r\n'
                ).encode('utf-8') + body

            client_socket.sendall(response)

        except Exception as e:
            print(f"处理请求时发生错误: {e}")
        finally:
            client_socket.close()

    def start(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
            server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind((self.host, self.port))
            server.listen(5)
            print(f"🌐 Server is running at http://{self.host}:{self.port}/")

            while True:
                client_socket, addr = server.accept()
                print(f"👤 连接来自: {addr}")
                thread = threading.Thread(target=self.handle_request, args=(client_socket,))
                thread.start()


if __name__ == '__main__':
    server = SimpleHTTPServer()
    server.start()

以访问命令行参数使用 sys.argv 列表来获取命令行输入

import socket
import os
import threading
import sys

class SimpleHTTPServer:
    def __init__(self, host='127.0.0.1', port=8080, static_dir='static'):
        self.host = host
        self.port = port
        self.static_dir = static_dir

    def get_content_type(self, file_path):
        if file_path.endswith('.html'):
            return 'text/html'
        elif file_path.endswith('.css'):
            return 'text/css'
        elif file_path.endswith('.js'):
            return 'application/javascript'
        elif file_path.endswith('.png'):
            return 'image/png'
        elif file_path.endswith('.jpg') or file_path.endswith('.jpeg'):
            return 'image/jpeg'
        elif file_path.endswith('.ico'):
            return 'image/x-icon'
        else:
            return 'text/plain'

    def handle_request(self, client_socket):
        try:
            request = client_socket.recv(1024).decode('utf-8')
            if not request:
                print("没有收到请求,关闭连接")
                return

            print('📥 收到请求:')
            print(request)

            path_line = request.splitlines()[0]
            method, path, _ = path_line.split()

            if path == '/':
                path = '/index.html'

            file_path = os.path.join(self.static_dir, path.lstrip('/'))

            if os.path.isfile(file_path):
                with open(file_path, 'rb') as f:
                    body = f.read()
                content_type = self.get_content_type(file_path)
                response = (
                    'HTTP/1.1 200 OK\r\n'
                    f'Content-Type: {content_type}; charset=utf-8\r\n'
                    f'Content-Length: {len(body)}\r\n'
                    '\r\n'
                ).encode('utf-8') + body
            else:
                body = b"<h1>404 Not Found</h1>"
                response = (
                    'HTTP/1.1 404 Not Found\r\n'
                    'Content-Type: text/html; charset=utf-8\r\n'
                    f'Content-Length: {len(body)}\r\n'
                    '\r\n'
                ).encode('utf-8') + body

            client_socket.sendall(response)

        except Exception as e:
            print(f"处理请求时发生错误: {e}")
        finally:
            client_socket.close()

    def start(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
            server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server.bind((self.host, self.port))
            server.listen(5)
            print(f"🌐 Server is running at http://{self.host}:{self.port}/")

            while True:
                client_socket, addr = server.accept()
                print(f"👤 连接来自: {addr}")
                thread = threading.Thread(target=self.handle_request, args=(client_socket,))
                thread.start()


if __name__ == '__main__':
    # 使用 sys.argv 获取命令行参数
    host = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
    port = int(sys.argv[2]) if len(sys.argv) > 2 else 8080
    static_dir = sys.argv[3] if len(sys.argv) > 3 else 'static'

    # 创建服务器实例,使用命令行参数
    server = SimpleHTTPServer(host=host, port=port, static_dir=static_dir)
    server.start()

执行格式:

python server_socket.py 127.0.0.1 8080 static
静态 web 服务器编程

发布者:LJH,转发请注明出处:https://www.ljh.cool/42427.html

Like (0)
LJHLJH
Previous 2025年5月26日 上午9:54
Next 2025年6月13日 上午11:24

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注