Python无依赖轻量级Web框架xweb:低于500行代码如何实现?

我用极少的代码了实现一款 web 框架,目标是用低于 1000 行的代码实现 flask 的核心功能, xweb 框架基于 python3.5 以上开发,实在是居家旅行良品.

github 地址:https://github.com/gaojiuli/xweb

我的目标是用最少的代码实现符合现状的 web 框架,欢迎同样有兴趣的同学一起参与进来

说明

基于3.5开发

安装

pip install xweb

基本用法

from xweb.application import XWeb

app = XWeb()

@app.route(’/:name/’) def call_my_name(name): return ‘hi {}!’.format(name)

app.listen(3000)

请求与相应

from xweb.globals import request

request.path request.query_string request.query request.files request.forms request.json request.ip request.hostname request.headers

from xweb.globals import response

response.headers response.status response.body

中间件

from xweb.application import XWeb

app = XWeb()

@app.middleware(‘request’) def print_on_request1(): print(“I print when a request is received by the server1”)

@app.middleware(‘request’) def print_on_request2(): print(“I print when a request is received by the server2”)

@app.middleware(‘response’) def print_on_response1(): print(“I print when a response is returned by the server1”)

@app.middleware(‘response’) def print_on_response2(): print(“I print when a response is returned by the server2”)

@app.route(’/:name/’) def call_my_name(name): return ‘hi {}!’.format(name)

app.listen(3000)

我的目标是用最少的代码实现符合现状的 web 框架,欢迎同样有兴趣的同学一起参与进来

github 地址:https://github.com/gaojiuli/xweb


Python无依赖轻量级Web框架xweb:低于500行代码如何实现?

29 回复

这个xweb框架的实现思路挺有意思的。核心就是基于Python标准库,用最少的代码实现基本的路由和请求处理。

下面是一个简化版的实现,大概100多行就能跑起来:

import socket
import re
from urllib.parse import parse_qs, urlparse
from http.server import BaseHTTPRequestHandler
from io import BytesIO

class Request:
    def __init__(self, method, path, headers, body):
        self.method = method
        self.path = path
        self.headers = headers
        self.body = body
        self.query = {}
        if '?' in path:
            self.path, query_string = path.split('?', 1)
            self.query = parse_qs(query_string)

class Response:
    def __init__(self, body='', status=200, content_type='text/html'):
        self.body = body
        self.status = status
        self.content_type = content_type

class XWeb:
    def __init__(self):
        self.routes = {}
        self.middlewares = []
    
    def route(self, path, methods=['GET']):
        def decorator(handler):
            for method in methods:
                self.routes[(method.upper(), path)] = handler
            return handler
        return decorator
    
    def add_middleware(self, middleware):
        self.middlewares.append(middleware)
    
    def handle_request(self, request):
        # 中间件处理
        for middleware in self.middlewares:
            request = middleware(request)
        
        # 路由匹配
        handler = self.routes.get((request.method, request.path))
        if handler:
            return handler(request)
        return Response('Not Found', 404)
    
    def run(self, host='127.0.0.1', port=8000):
        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 running on http://{host}:{port}")
            
            while True:
                conn, addr = server.accept()
                with conn:
                    data = conn.recv(1024)
                    if data:
                        # 解析HTTP请求
                        request_line, *headers_body = data.decode().split('\r\n', 1)
                        method, path, _ = request_line.split()
                        
                        # 解析headers
                        headers_part, body_part = headers_body[0].split('\r\n\r\n', 1) if '\r\n\r\n' in headers_body[0] else (headers_body[0], '')
                        headers = {}
                        for line in headers_part.split('\r\n'):
                            if ': ' in line:
                                key, value = line.split(': ', 1)
                                headers[key] = value
                        
                        request = Request(method, path, headers, body_part)
                        response = self.handle_request(request)
                        
                        # 构建HTTP响应
                        response_headers = f"HTTP/1.1 {response.status} OK\r\n"
                        response_headers += f"Content-Type: {response.content_type}\r\n"
                        response_headers += f"Content-Length: {len(response.body)}\r\n"
                        response_headers += "\r\n"
                        
                        conn.sendall(response_headers.encode() + response.body.encode())

# 使用示例
app = XWeb()

@app.route('/')
def home(request):
    return Response('<h1>Hello XWeb!</h1>')

@app.route('/api/data', methods=['GET', 'POST'])
def api_data(request):
    if request.method == 'GET':
        return Response('{"status": "ok"}', content_type='application/json')
    else:
        return Response('{"status": "created"}', 201, 'application/json')

if __name__ == '__main__':
    app.run()

关键实现点:

  1. 直接使用socket处理TCP连接,避免依赖
  2. 手动解析HTTP请求头,实现基本的路由匹配
  3. 用装饰器注册路由处理函数
  4. 支持中间件链式处理

要压缩到500行内,就得砍掉高级功能,只保留核心的路由和请求响应循环。真正的xweb可能还加了模板渲染、静态文件这些,但基本原理就这么简单。

总结:用标准库造轮子挺练手的。

那个。。。 method not allowed 不是 405 么😓

def listen(self, port):
from wsgiref.simple_server import make_server
server = make_server(‘127.0.0.1’, port, self)
print(‘serve on 127.0.0.1:{port}’.format(port=port))
server.serve_forever()
…建议把这个裁了。。。换成可以使用任意 wsgi

坐等日志、队列、 ORM(Postgresql&MySQL)。

讲真 Auth 就不要了

状态码从网上搞得,还没有专门整理

雪亮的眼!

这个是开发阶段选用的,只要符合 wsgi 就可以,实际部署的时候应选用 uwsgi 等工具

orm 我会重新启动一个项目,思路是分离出 django orm ,删减不常用的功能。我不打算把 orm 耦合进来,但是针对 xweb 定制一款符合现状的 orm 系统还是必要的。队列与日志同理,采用无耦合的形式开发。

想法不错

不过要说代码少的话,其实有个框架叫 bottle 的,记得代码很少,不知道还有人在用么

我的灵感来自 bottle , flask 和 sanic 三款框架,其中 bottle 和 flask 中为了 python2.7 添加太多代码,而 sanic 并非基于 wsgi ,有太多的依赖。这是我的初衷

这种库居然也能说成框架

可以啊, web.py 还是框架呢

哦。你这个也就是一个 action dispatcher ,一个框架重点在于 ORM

如你所说的话,Flask 和 Sanic 也不算框架咯?

很多框架都不自带 ORM ,怎么成重点了

orm 在我的计划之中,但是我不打算将它们耦合起来就像现在 Django ,我要的效果是 xweb 能快速地使用 peewee , sqlalchemy 等 orm ,也能用针对它开发的 orm 。同时这个 orm 应当能够和 flask , sanic 等结合使用。而不是强耦合地植入。

模板语言也不搞了吧。

json 部分弄好一点,实用性提高不少。

你的想法和我一样, xweb 简化满足用于接口开发即可

其实我只想要一个类似 php 那种一键部署的傻瓜工具

感谢你的建议, python 可以很容易实现傻瓜地部署,我会在项目完整后编写这样的脚本。

我在写的 web 框架也是这样搭建测试 HTTP 的,(基本所有 python web 框架都是使用 wsgiref 的 make_server 来本地测试的)

他这种写法并没有问题。 是要是对象里面有 call 函数 满足 wsgi 就可以了。

闲着没事的话可以给 bottle 增加 asyncIo 支持,就像 sanic 对 Flask 做的一样。

我可不乐意写那些兼容 python2 的代码

简单易懂,学习下,看看有没有机会做点贡献

建议去完善 sanic ,而不是再造一个轮子

sanic 使用 uvloop ,造成了无法使用像 flask 中的全局变量 request,response,g 等,并且它依赖于 aiofiles , httptools , ujson , uvloop 这几个库,如果这几个库更新,那么 sanic 不得不被牵着鼻子走. 我想实现的是无第三方依赖,并且摒弃 python2 .

bottle 本来就是兼容 Python2 和 3 的,但是 bottle 现在不支持 asyncio 。

我的意思是既然开发基于 python3, 那么所有为了 Python2 而生的代码都是多余的.

回到顶部