自己动手撸Python框架:4. 路径映射-1

本文介绍了Python web开发中URL映射的基础知识,包括使用globals()获取类实例、urllib库解析URL以及正则表达式进行路径匹配。通过示例展示了如何创建类实例、解析URL结构以及利用正则表达式从URL中提取参数。这些基础知识对于理解web框架的URL映射功能至关重要。

只考虑简单的路径映射,会涉及到一些简单的正则表达式。web.py里映射用的是列表,每个映射两个元素,为了写代码简便,直接用字典好了。在开始内容之前,我们先做些准备工作。

globals的花招

给你一个名字,如何查看有没有同名的类然后再创建一个实例?

import inspect

class TestA:
    def info(self):
        print('TestA')
    
def create(cls_name):
    g = globals()
    if cls_name in g:
        if inspect.isclass(g[cls_name]):
            return g[cls_name]()
    return None
    
ta = create('TestA')
tb = create('TestB')
ta.info()
print(tb)

在Python里你每定义一个类,添加一个变量,就会在全局增加一个名字映射,方便执行的时候查找。用globals()可以返回当前代码里包含的所有名字及对应的对象。所以g['TestA']()和TestA()是等价的。而TestB因为全局没有这个类所以返回None。inspect.isclass是判断某个变量是不是类。

URL解析

URL的标准格式如下,Python的urllib库提供了urlparse函数帮助我们快速解析URL。

from urllib.parse import urlparse

url = 'http://www.xyz.com/abc/def;params?a=1&b=2&c=zzz#fragment'
p = urlparse(url)
print('scheme: ' + p.scheme)
print('netloc: ' + p.netloc)
print('path: ' + p.path)
print('params: ' + p.params)
print('query: ' + p.query)
print('fragment: ' + p.fragment)

 执行后,可以看到各部分信息如下:

scheme: http
netloc: www.xyz.com
path: /abc/def
params: params
query: a=1&b=2&c=zzz
fragment: fragment

正则表达式匹配

在mapping里我们定义了路径匹配的规则,具体实现是使用正则表达式匹配。web.py在设计的时候考虑到效率,针对正则表达式的匹配进行了缓存处理。具体实现可以看源代码utils.py里Memoize类的实现。我们在这里简化一下代码,假设mapping为('^/index/name=(.*)&age=(.*)$', 'index'),现在输入的路径是/index/name=ZV&age=18。我们可以通过以下代码完成路径匹配并获得参数。

import re

class proxy:
    def __init__(self):
        self.match = None
        
    def __call__(self, match):
        self.match = match
        
def match(pattern, cls, value):
    p = proxy()
    compiled = re.compile(pattern)
    compiled.sub(p.__call__, value)
    cls, args = compiled.sub(cls, value), p.match
    return cls, args

if __name__ == '__main__':
    pattern = '/index/name/(.*)/age/(.*)'
    cls = 'index'
    value = '/index/name/ZV/age/18'
    cls, args = match(pattern, cls, value)
    print('Class:' + cls)
    if args:
        print('Args: ' + str([x for x in args.groups()]))

程序执行结果:

Class:index
Args: ['ZV', '18']

在了解了这些预备知识后,在下一章我们就会为框架添加URL映射功能。

<think>好的,我现在需要解决用户在使用Python 3内置的HTTP服务器时遇到的404文件未找到的问题。用户之前已经询问过加载缓慢的问题,现在转向了404错误。我需要结合用户提供的引用和之前的回答来给出解决方案。 首先,用户提供的引用中提到了创建app.py文件、os.system()的输出问题、SQLite数据库锁定以及Protobuf的FieldDescriptor。不过这些引用可能与当前问题关联不大,但用户提示要参考站内引用,所以我需要确认是否有相关信息可用。例如,引用[3]提到的路径问题可能相关,但主要问题还是404错误,所以可能需要更多关注文件路径和服务器配置。 用户当前的问题是关于Python 3的http.server返回404错误。我需要分析可能的原因和解决方法。根据之前关于http.server的回答,服务器默认在启动目录下提供文件,因此检查路径是否正确是关键。可能的错误原因包括文件路径错误、URL拼写错误、服务器未在正确目录启动,或者文件权限问题。 接下来,我需要组织解决方案,分步骤说明如何排查和解决。例如,检查启动目录是否正确,确保请求的文件存在于该目录下,处理特殊字符,调整URL路径等。同时,可能需要提到自定义请求处理器来处理特定情况,比如重定向或动态内容。 另外,用户之前的问题中提到了多线程服务器和压缩处理,但当前问题属于文件未找到,可能需要不同的处理方式。需要确保用户理解服务器的基础配置和文件结构。 最后,生成相关问题,帮助用户进一步学习,比如处理动态路由、自定义错误页面、处理符号链接或跨平台路径问题等。 需要确保回答结构清晰,步骤明确,代码示例正确,并且引用之前的建议(如使用多线程服务器是否有帮助)。同时,使用中文,正确使用LaTeX格式,并添加相关引用标记。</think>### 解决 Python3 `http.server` 返回 404 文件未找到的完整指南 Python 内置的 `http.server` 默认以当前启动目录为根目录提供文件服务。若出现 **404 File Not Found** 错误,通常由以下原因导致: --- #### 一、原因分析与验证步骤 1. **启动目录与文件路径不匹配** - 服务器默认从启动命令执行的目录开始查找文件。例如: ```bash cd /project/files && python3 -m http.server 8000 # 此时只能访问 /project/files 下的文件 ``` - 如果请求 `http://localhost:8000/image.jpg`,服务器实际会查找 `/project/files/image.jpg`。若文件不存在则返回 404。 2. **URL 路径拼写错误** - 文件名大小写敏感(尤其在 Linux/macOS 系统中) `File.jpg` ≠ `file.jpg` - 特殊字符未转义:空格需替换为 `%20`,如 `my%20document.txt` 3. **文件权限问题** - 服务器进程可能因权限不足无法读取目标文件(常见于 Linux 系统) --- #### 二、解决方案与代码示例 ##### 方法一:明确启动目录与文件结构 1. **检查当前工作目录** ```python import os print("当前服务器根目录:", os.getcwd()) # 在启动服务器前验证路径 ``` 2. **启动时指定目录**(Python 3.7+ 支持 `--directory` 参数) ```bash python3 -m http.server 8000 --directory /your/target/folder ``` ##### 方法二:自定义请求处理器修复路径解析 若需处理特殊路径(如子目录映射),可继承 `SimpleHTTPRequestHandler`: ```python from http.server import SimpleHTTPRequestHandler, HTTPServer import os class CustomHandler(SimpleHTTPRequestHandler): def translate_path(self, path): # 将 /static/ 映射到本地 assets 目录 if path.startswith('/static/'): return os.path.join('assets', path[8:]) return super().translate_path(path) server = HTTPServer(('0.0.0.0', 8000), CustomHandler) server.serve_forever() ``` 此时访问 `http://localhost:8000/static/image.jpg` 将指向 `./assets/image.jpg`[^1]。 ##### 方法三:动态生成内容避免物理文件依赖 对于不存在的物理文件,可通过编程方式返回内容: ```python class DynamicHandler(SimpleHTTPRequestHandler): def do_GET(self): if self.path == '/time': self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write(f"Current time: {datetime.now()}".encode()) else: super().do_GET() # 默认文件服务 # 启动代码同上 ``` ##### 方法四:调试请求日志 添加详细日志记录每个请求的路径和解析结果: ```python class DebugHandler(SimpleHTTPRequestHandler): def do_GET(self): print(f"[DEBUG] 请求路径: {self.path} → 解析为: {self.translate_path(self.path)}") super().do_GET() ``` --- #### 三、高级排查技巧 1. **使用 `curl -v` 验证响应头** ```bash curl -v http://localhost:8000/missing_file.html ``` 观察 `Content-Length: 0` 或 `Content-Type: text/html; charset=utf-8` 确认是否由服务器返回的 404 2. **检查文件权限**(Linux/macOS) ```bash ls -l /path/to/file # 确认其他用户有读权限(至少 r--) chmod o+r filename # 添加其他用户读权限 ``` 3. **处理隐藏文件** 默认不显示以 `.` 开头的文件,需显式请求:`http://localhost:8000/.htaccess` --- ### 结论 通过路径验证、自定义处理器和权限调整可解决 90% 的 404 错误。若需更复杂的路由逻辑,建议迁移至 Flask(轻量级)或 Django(全功能框架)[^1]。 ```python # 快速 Flask 示例 from flask import Flask, send_from_directory app = Flask(__name__) @app.route('/files/<path:name>') def serve_file(name): return send_from_directory('/custom/path', name) if __name__ == '__main__': app.run(port=8000) ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值