博客
关于我
Python http.server 服务器
阅读量:634 次
发布时间:2019-03-15

本文共 5410 字,大约阅读时间需要 18 分钟。

Python-simple-http-server

这是一个轻量级的基于 Python http.server 编写的服务器,你可以非常容易的搭建一个 Restful API。其中一些请求的转发等参考了 SpringMVC 的设计。

支持的 Python 版本

  • Python 2.7
  • 3.6+
  • 3.5 也应该支持,没有在3.5环境测试过

为什么选择这个项目?

  • 轻量级
  • 支持过滤器链
  • Spring MVC 风格的请求映射配置
  • 简单易用
  • 编写风格自由

安装

pip install simple_http_server

编写控制器

配置路由信息

我们接下来将处理请求的函数命名为控制器函数(Controller Function)。类似 Spring MVC,我们使用描述性的方式来将配置请求的路由(在 Java 中,我们会使用标注 Annotation,而在 Python,我们使用 decorator,两者在使用时非常类似)。

基础的配置如下,该例子中,请求 /index 将会路由到当前的方法中。

from simple_http_server import request_map@request_map("/index")def your_ctroller_function():    return "Hello, World!"

@request_map 会接收两个参数,第二个参数会指定当前的控制器函数会处理请求中哪些方法(Method),以下的例子中的方法,仅会处理方法为 GET 的请求。

@request_map("/say_hello", method="GET")def your_ctroller_function():    return "Hello, World!"

method 参数同时也可以是一个列表,以下的例子中,该控制器函数会处理方法为 GET、POST、PUT 的请求。

@request_map("/say_hello", method=["GET", "POST", "PUT"])def your_ctroller_function():    return "Hello, World!"

匹配路由时,除了指定具体的路径之外,你还可以指定路径的某一段是可变的,这部分可变的将会作为路径参数放入请求中,如何取得这些路径参数我们将会在 取得请求参数 一节具体说明。@request_map 的配置如下。该配置下,/say/hello/to/world 和 /say/hello/to/jhon 等 URL 都能访问该控制器方法。

@request_map("/say_hello/to/{name}", method=["GET", "POST", "PUT"])def your_ctroller_function():    return "Hello, World!"

你可以给一个控制器函数增加多个 @request_map。

@request_map("/")@request_map("/index")def index():    return "Hello, World!"

取得请求中的信息

参考了 Spring MVC 的设计,获取请求方法的方式非常自由。其中最基本的方法是取得 Request 对象,该对象中包含了所有其他方式能够获取的内容。

from simple_http_server import Request@request_map("/say_hello/to/{name}", method=["GET", "POST", "PUT"])def your_ctroller_function(req=Request()):    """ 请注意关键字参数传入的默认参数是一个 Request 对象,而不是类本身。 """    # 该请求的方法,可能是 "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" 中的一个    print(req.method)     # 该请求的路径,就是 /say/hello/to/xxx    print(req.path)     # 一个 dict 对象,包含了所有的头部参数。    print(req.headers)     # 一个 dict 对象,包含了请求的参数,包括了来源于QueryString与 body 中的参数    # 该对象仅存储一个参数,如果同一个参数名传入了多个值,该对象只记录第一个值。    print(req.parameter)     # 一个 dict 对象,类似,req.parameter,但该对象包含了所有的参数    # 该对象的值总是会返回一个列表,即使一个参数名只传入了一个参数。    print(req.parameters)     # 返回 query string    print(req.query_string)     # 返回一个 Cookies 对象,该对象是 http.cookies.SimpleCookie 的子类    print(req.cookies)     # 一个 dict 对象,包含了所有的路径上的参数,本例中是 {"name": "xxx"}    print(req.path_values)     # 请求体部分,在 3.6 中是一个 bytes 对象。2.7 中是一个 str 对象    print(req.body)     # 当你的请求的 Content-Type 是 application/json 时,框架会自动将请求体中的 JSON 对象加载为一个dict对象。    print(req.json)     return "Hello, World!"

我们还可以通过更直接的参数和关键字参数来获取请求中的信息,使得编码更加简洁和方便。

from simple_http_server import request_map@request_map("/say_hello/to/{name}", method=["GET", "POST", "PUT"])def your_ctroller_function(        user_name,  # 传入 req.parameter["user_name"],如果该参数为空,则会响应为 400 参数错误        password,   # 传入 req.parameter["password"],如果参数为空,则会响应为 400 参数错误        nickName="",  # 传入 req.parameter["nickName"],如果参数为空,则会传入 ""        age=16,      # 传入 int(req.parameter["age"]),如果传入空则传入 16,如果传入的不是数字类型,会返回 400 参数错误        male=True,   # 传入 0, false, 空字符串 为 False,其他均为 True,如果不传入,传入这里指定的默认值        skills=[],    # 传入 req.parameters["skills"],会返回一个数组,如果没有传入任何的内容,则返回这里指定的数组        extra={}     # 传入 json.loads(req.parameter["extra"]),如果不传入则传入这里指定的 dict 对象,如果传入的字符串不是 JSON 格式,则响应为 400 参数错误):    return "Hello, World!"

响应请求

从上述的例子中可以看出,取得请求中的参数我们有许多方式,这个给了开发者很高的自由度来编写这些信息。而响应的方法一样具有各种方法。

除了 HTML5 格式的字符串,我们还可以返回以下的内容:

return {"success": True, "message": "Success!"}
return "
"
return "some other string value"
from simple_http_server import HttpErrorraise HttpError(404, "page not found")
raise Exception()
from simple_http_server import Redirectreturn Redirect("/redirect/to/this/path")
from simple_http_server import StaticFilereturn StaticFile("/path/to/file.xml", content_type="text/xml")
from simple_http_server import Responsefrom http.cookies import SimpleCookieres = Response(status_code=200)res.headers["Content-Type"] = "text/html"res.set_header("userToken", "user_id_token_xxxx")  # set_header() 会覆盖之前设置的信息res.add_header("userToken", "xxxx")  # add_header() 会增加多一个信息res.cookies = SimpleCookie()res.cookie["userInfo"] = "ABC"res.cookie["userInfo"]["path"] = "/"res.body = "hello world"return res
from simple_http_server import Headersfrom simple_http_server import Cookiesres_cookies = Cookies()res_cookie["userInfo"] = "ABC"res_cookie["userInfo"]["path"] = "/"return 200, Headers({"userToken": "user_id_token_xxx"}), res_cookie, {"success": True, "message": "success!"}, "这个字符串会被忽略"
return Headers({"userToken": "user_id_token_xxx"}), {"success": True, "message": "success!"}

编写过滤器

参考 Java 的设计,我们增加了过滤器链式的设计,这个给了你一定的面向切面编码的能力,虽然比较弱,但是做一些权限验证,日志记录等也是够用的。

from simple_http_server import filter_map# 请注意!过滤器的字符串配置是一个正则表达式的字符串。@filter_map("^/tuple")def filter_tuple(ctx):    print("---------- through filter ---------------")    # 在过滤器中加入一些信息到请求头中    ctx.request.headers["filter-set"] = "through filter"    if "user_name" not in ctx.request.parameter:        ctx.response.send_redirect("/index")    elif "pass" not in ctx.request.parameter:        ctx.response.send_error(400, "pass should be passed")        # 你也可以使用以下代码,通过抛出异常的方式来返回错误的响应信息。        # raise HttpError(400, "pass should be passed")    else:        # 如果你需要进入下一个过滤器链条或者调用请求处理的函数,必须显式调用以下的方法。        ctx.do_chain()

启动服务器

import simple_http_server.server as server# 如果你的控制器代码(处理请求的函数)放在别的文件中,那么在你的 main.py 中,你必须将他都 import 进来。import my_test_ctrldef main(*args):    server.start()if __name__ == "__main__":    main()

转载地址:http://kwplz.baihongyu.com/

你可能感兴趣的文章
文件系统的层次结构
查看>>
减少磁盘延迟时间的方法
查看>>
vue(渐进式前端框架)
查看>>
权值初始化和与损失函数
查看>>
vscode设置eslint保存文件时自动修复eslint错误
查看>>
最大半连通子图
查看>>
Remove Extra one 维护前缀最大最小值
查看>>
GitHub完整记录数据库GHTorrent的下载和安装经验
查看>>
Gradle实战四:Jenkins持续集成
查看>>
wgcloud运维监控系统错误:防篡改校验错误次数大于10次,不再上报数据
查看>>
iOS 开发官方文档链接收集
查看>>
vue报错 created hook错误
查看>>
12-面向对象1
查看>>
HDU - 4109 Instrction Arrangement
查看>>
JQuery--手风琴,留言板
查看>>
MFC 自定义消息发送字符串
查看>>
Linux操作系统的安装与使用
查看>>
C++ 继承 详解
查看>>
OSPF多区域
查看>>
Docker入门之-镜像(二)
查看>>