码迷,mamicode.com
首页 > 编程语言 > 详细

[Python WEB开发] 使用WSGI开发类Flask框架 (二)

时间:2017-12-26 21:56:18      阅读:427      评论:0      收藏:0      [点我收藏+]

标签:serve   apn   content   port   应该   users   第三方   图片   form   

 

 

 

WSGI     Web服务器网关接口

WSGI主要规定了Web服务器如何与Web应用程序进行通信,以及如何将Web应用程序链接在一起来处理一个请求。

 

 

技术分享图片 

 

wsgiref  Python中的WSGI参考模块

 

一、WSGI 应用程序端:

1、 根据WSGI定义,应用程序应该是可调用对象

2、该可调用对象必须有两个固定参数:一个是含有服务器环境变量的字典,另一个是可调用对象,该对象使用HTTP状态码和会返回给客户端的HTTP头来初始化响应

environ 变量包含一些熟悉的环境变量,如HTTP_HOST,HTTP_USER_AGENT,REMOTE_ADDR,REQUEST_METHOD,SERVER_PORT,部分如下:

Hello world!

GATEWAY_INTERFACE = ‘CGI/1.1‘
HTTP_ACCEPT = ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8‘
HTTP_ACCEPT_ENCODING = ‘gzip, deflate, br‘
HTTP_ACCEPT_LANGUAGE = ‘zh-CN,zh;q=0.9,en;q=0.8‘
HTTP_CONNECTION = ‘keep-alive‘
HTTP_HOST = ‘127.0.0.1:9999‘
HTTP_USER_AGENT = ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36‘
QUERY_STRING = ‘‘
REMOTE_ADDR = ‘127.0.0.1‘
REQUEST_METHOD = ‘GET‘
SERVER_PORT = ‘9999‘
SERVER_PROTOCOL = ‘HTTP/1.1‘
SERVER_SOFTWARE = ‘WSGIServer/0.2‘

 

3、这个可调用对象必须返回一个可迭代对象用于组成响应

 

 

wsgiref参考库中有以下几个子模块:

* util -- 一些有用的功能和包装

* headers -- 管理响应头

* handlers -- 为server/gateway实现如何处理的基类

* simple_server -- 实现一个简单的WSGI HTTP服务器

* validate -- 位于应用程序和server之间检测错误的校验包装

 

 

二、WSGI HTTP Server端的使用

1. 启动一个简单的WSGI HTTP Server:

# 简单web 1
from wsgiref.simple_server import make_server


def demo_app(environ, start_response): #copy自simple_server模块
    from io import StringIO
    stdout = StringIO()
    print("Hello world!", file=stdout)
    print(file=stdout)
    h = sorted(environ.items())
    for k, v in h:
        print(k, ‘=‘, repr(v), file=stdout)
    start_response("200 OK", [(‘Content-Type‘, ‘text/plain; charset=utf-8‘)])
    return [stdout.getvalue().encode("utf-8")]


ip = ‘127.0.0.1‘
port = 9999
server = make_server(ip, port, demo_app)
server.serve_forever()

server.server_close()


wsgiref.simple_server.make_server(host, port, app, server_class=WSGIServer, handler_class=WSGIRequestHandler)
启动一个WSGI服务器,必须传入host, port, app三个参数。

 

在运行这段程序之后,就已经实现了一个监听在9999端口的webServer,下面是服务端运行状态和浏览器中访问结果:

 

访问 http://127.0.0.1:9999/

#server端运行状态:
127.0.0.1 - - [26/Dec/2017 15:01:13] "GET / HTTP/1.1" 200 2128
127.0.0.1 - - [26/Dec/2017 15:01:13] "GET /favicon.ico HTTP/1.1" 200 2096


#浏览器访问结果:
Hello world!

Apple_PubSub_Socket_Render = ‘/private/tmp/com.apple.launchd.Gx10g4snot/Render‘
CLICOLOR = ‘1‘
CONTENT_LENGTH = ‘‘
CONTENT_TYPE = ‘text/plain‘
GATEWAY_INTERFACE = ‘CGI/1.1‘
GREP_OPTIONS = ‘--color=auto‘
HOME = ‘/Users/ihoney‘
HTTP_ACCEPT = ‘text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8‘
HTTP_ACCEPT_ENCODING = ‘gzip, deflate, br‘
HTTP_ACCEPT_LANGUAGE = ‘zh-CN,zh;q=0.9,en;q=0.8‘
HTTP_CONNECTION = ‘keep-alive‘
HTTP_HOST = ‘127.0.0.1:9999‘
HTTP_UPGRADE_INSECURE_REQUESTS = ‘1‘
HTTP_USER_AGENT = ‘Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36‘
LC_CTYPE = ‘zh_CN.UTF-8‘
......

  

2. 自定义响应的网页内容:

# 简单web 2
from wsgiref.simple_server import make_server

def application(environ:dict,start_response):
    # print(type(environ),environ)
    html = "<h1>北京欢迎你</h1>"
    # start_response("200 OK", [(‘Content-Type‘,‘text/plain; charset=utf-8‘)]) #文本格式
    start_response("200 OK", [(‘Content-Type‘, ‘text/html; charset=utf-8‘)]) #html格式

    return [html.encode()]


ip = ‘127.0.0.1‘
port =9999
server = make_server(ip,port,application)
server.serve_forever()

server.server_close()


#运行结果:
127.0.0.1 - - [26/Dec/2017 15:38:55] "GET / HTTP/1.1" 200 24
127.0.0.1 - - [26/Dec/2017 15:38:55] "GET /favicon.ico HTTP/1.1" 200 24

  浏览器访问结果:

技术分享图片

  simple_server 只是参考,不可用于生产环境。

 

 

三、QUERY_STRING 查询字符串的解析

1. 使用cgi模块:

# 简单web 3 使用cgi模块解析query_string
import cgi
from wsgiref.simple_server import make_server

def application(environ:dict,start_response):
    qstr = environ.get("QUERY_STRING")
    print(qstr)
    # ?id=5&name=ihoney&age=18,19
    print(cgi.parse_qs(qstr)) #字典,value为列表类型
    print(cgi.parse_qsl(qstr)) #二元组列表

    html = "<h1>北京欢迎你</h1>"
    start_response("200 OK", [(‘Content-Type‘, ‘text/html; charset=utf-8‘)])
    return [html.encode()]


ip = ‘127.0.0.1‘
port =9999
server = make_server(ip,port,application)
server.serve_forever()

server.server_close()

#浏览器访问http://127.0.0.1:9999/?id=5&name=ihoney&age=18,19
#运行结果:
127.0.0.1 - - [26/Dec/2017 15:51:17] "GET /?id=5&name=ihoney&age=18,19 HTTP/1.1" 200 24
id=5&name=ihoney&age=18,19
{‘age‘: [‘18,19‘], ‘name‘: [‘ihoney‘], ‘id‘: [‘5‘]}
[(‘id‘, ‘5‘), (‘name‘, ‘ihoney‘), (‘age‘, ‘18,19‘)]

  在写的时候IDE工具就会提示CGI模块已经过期了,建议使用urllib库。

2. 使用urllib库

# 简单web 4 使用urllib模块解析query_string
from urllib import parse
from wsgiref.simple_server import make_server

def application(environ:dict,start_response):
    qstr = environ.get("QUERY_STRING")
    print(qstr)
    # ?id=5&name=ihoney&age=18,19
    print(parse.parse_qs(qstr)) #字典,value为列表类型
    print(parse.parse_qsl(qstr)) #二元组列表

    html = "<h1>北京欢迎你</h1>"
    start_response("200 OK", [(‘Content-Type‘, ‘text/html; charset=utf-8‘)])
    return [html.encode()]


ip = ‘127.0.0.1‘
port =9999
server = make_server(ip,port,application)
server.serve_forever()

server.server_close()

#浏览器访问:http://127.0.0.1:9999/?id=5&name=ihoney&age=18,19
#运行结果:
id=5&name=ihoney&age=18,19
{‘id‘: [‘5‘], ‘age‘: [‘18,19‘], ‘name‘: [‘ihoney‘]}
[(‘id‘, ‘5‘), (‘name‘, ‘ihoney‘), (‘age‘, ‘18,19‘)]
127.0.0.1 - - [26/Dec/2017 15:58:40] "GET /?id=5&name=ihoney&age=18,19 HTTP/1.1" 200 24

  

3. 使用第三方库webob

pip3 install webob

第三方库webob可以把环境数据的解析封装成对象,使用时直接调用。

3.1 webob.Request

#简单web 5,使用第三方库webob解析
from wsgiref.simple_server import make_server
from webob import Request, Response


def application(environ: dict, start_response):
    request = Request(environ)
    print(request.method)
    print(request.path)
    print(request.GET)
    print(request.POST)
    print(request.params)
    print(request.query_string)

    html = "<h1>北京欢迎你</h1>"
    start_response("200 OK", [(‘Content-Type‘, ‘text/html; charset=utf-8‘)])
    return [html.encode()]


ip = ‘127.0.0.1‘
port = 9999
server = make_server(ip, port, application)
server.serve_forever()

server.server_close()

#浏览器访问:http://127.0.0.1:9999/index.html?id=5&name=tom,jerry&age=17&age=18,19
#运行结果:
GET
/index.html
GET([(‘id‘, ‘5‘), (‘name‘, ‘tom,jerry‘), (‘age‘, ‘17‘), (‘age‘, ‘18,19‘)])
<NoVars: Not a form request>
NestedMultiDict([(‘id‘, ‘5‘), (‘name‘, ‘tom,jerry‘), (‘age‘, ‘17‘), (‘age‘, ‘18,19‘)])
id=5&name=tom,jerry&age=17&age=18,19
127.0.0.1 - - [26/Dec/2017 16:51:41] "GET /index.html?id=5&name=tom,jerry&age=17&age=18,19 HTTP/1.1" 200 24

  

3.2 webob.Resphone

#
from wsgiref.simple_server import make_server
from webob import Request, Response


def application(environ: dict, start_response):
    res = Response("<h1>北京欢迎你</h1>")
    return res(environ,start_response)   #__call__


ip = ‘127.0.0.1‘
port = 9999
server = make_server(ip, port, application)
server.serve_forever()

server.server_close()

#浏览器访问:http://127.0.0.1:9999/index.html?id=5&name=tom,jerry&age=17&age=18,19
#运行结果:
127.0.0.1 - - [26/Dec/2017 18:08:03] "GET /index.html?id=5&name=tom,jerry&age=17&age=18,19 HTTP/1.1" 200 24

  

3.3 MultiDict

Request.GET、Request.POST 都是MultiDict字典

# multidict
from webob.multidict import MultiDict

md = MultiDict()
md[1] = ‘b‘
md.add(1,‘a‘)

print(md.get(1)) #只返回一个值
print(md.getall(1))
# print(md.getone(1)) #要求key的value只能有一个,否则抛KeyError异常
print(md.get(‘c‘)) #不存在返回默认值None
#运行结果:
a
[‘b‘, ‘a‘]
None

 

3.4 webob.dec.wsgify 装饰器

将一个函数变成一个WSGI应用程序

# wsgify
from wsgiref.simple_server import make_server
from webob import Request, Response,dec


def application(environ: dict, start_response):
    res = Response("<h1>北京欢迎你</h1>")
    #200 OK
	#[(‘Content-Type‘, ‘text/html; charset=UTF-8‘), (‘Content-Length‘, ‘0‘)]
    return res(environ,start_response)   #__call__

@dec.wsgify
def app(request:Request) -> Response:
	return Response("<h1>Welcome to BeiJing</h1>")


ip = ‘127.0.0.1‘
port = 9999
# server = make_server(ip, port, application)
server = make_server(ip, port, app)
server.serve_forever()

server.server_close()

#浏览器访问:http://127.0.0.1:9999/index.html?id=5&name=tom,jerry&age=17&age=18,19
#运行结果:
127.0.0.1 - - [26/Dec/2017 20:25:14] "GET /index.html?id=5&name=tom,jerry&age=17&age=18,19 HTTP/1.1" 200 27
127.0.0.1 - - [26/Dec/2017 20:25:14] "GET /favicon.ico HTTP/1.1" 200 27

  

 改进:

from wsgiref.simple_server import make_server
from webob import Request, Response,dec


@dec.wsgify
def app(request:Request) -> Response:
	return Response("<h1>Welcome to BeiJing.</h1>")

if __name__ == "__main__":
	ip = ‘127.0.0.1‘
	port = 9999
	server = make_server(ip, port, app)
	try:
		server.serve_forever()
	except KeyBoardInterrupt:
		pass
	finally:
		server.server_close()

  

 

总结:

本文简单介绍了WSGI、WSGI HTTP Server、查询字符串的处理、第三方库webob的一些用法。

 

 

 

 

 

 

 

 

 

 

 

 

 

  

[Python WEB开发] 使用WSGI开发类Flask框架 (二)

标签:serve   apn   content   port   应该   users   第三方   图片   form   

原文地址:https://www.cnblogs.com/i-honey/p/8110848.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!