最近web服務器知識,中間懶癌犯了,斷了一兩天後思路有點接不上來,手頭上也有其他事情要做,先簡單的總結下學習進度,很多重要的功能都沒跑通,目前flask只是簡單實現路由分顯示不同的結果,cgi可以根據不同的靜態資源或者py腳本文件路徑顯示不同的結果。目前來説文章亮點就是解耦做的還行,有一定的可擴展性
簡單的仿flask實現路由分發
from wsgiref.simple_server import make_server
''''
WSGI規定:
1. 應用程序需要是一個可調用的對象
2. 可調用對象接收兩個參數
3.可調用對象要返回一個值,這個值是可迭代的。
具體參考附錄一,pep-0333標準
'''
class SimServer(object):
def __init__(self):
self.url_map = {}
def __call__(self, environ, start_response):
status = u'200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
data=self.dispatch_request(environ)
return [data.encode('utf-8'),]
def run(self, ip=None, host=None):
if not ip:
ip = ''
if not host:
host = 8080
httpd = make_server(ip, host, self)
httpd.serve_forever()
#路由裝飾器
def route(self, rule):
def decorator(f):
self.url_map[rule.lstrip('/')] = f
return f
return decorator
#路由的分發
def dispatch_request(self, request):
print(request)
path = request.get('PATH_INFO', '').lstrip('/')
print(path)
return self.url_map[path]() # 從url_map中找到對應的處理函數,並調用
#創建一個app
app=SimServer()
@app.route('/index')
def index():
return 'hello world'
@app.route('/login')
def login():
return 'please login'
if __name__=="__main__":
app.run()
if __name__=="__main__":
app.run()
CGI web服務器,靜態資源的轉發
handler.py
import os
import subprocess
class BaseHandler(object):
'''Parent for case handlers.'''
def handle_file(self, handler, full_path):
try :
with open(full_path, 'rb') as reader:
content = reader.read()
handler.send_content(content)
except IOError as msg:
msg = "'{0}' cannot be read: {1}".format(full_path, msg)
handler.handle_error(msg)
def index_path(self, handler):
return os.path.join(handler.full_path, 'index.html')
def test(self, handler):
assert False, 'Not implemented.'
def act(self, handler):
assert False, 'Not implemented.'
#處理首頁
class Case_directory_idnex_file(BaseHandler):
def test(self, handler):
return (os.path.isdir(handler.full_path) and
os.path.isfile(self.index_path(handler)))
def act(self, handler):
self.handle_file(handler, self.index_path(handler))
#處理普通html文件
class Case_existing_file(BaseHandler):
def test(self, handler):
return os.path.isfile((handler.full_path))
def act(self, handler):
self.handle_file(handler,handler.full_path)
#處理python腳本
class Case_cgi_file(BaseHandler):
def run_cgi(self, handler):
print('dfs')
print(handler.full_path)
data=subprocess.getoutput(['python',handler.full_path])
print('data={}'.format(data))
#python3默認使用unicode,需要encode('utf-8')
return handler.send_content(data.encode('utf-8'))
def test(self,handler):
return os.path.isfile(handler.full_path) and \
handler.full_path.endswith('.py')
def act(self,handler):
self.run_cgi(handler)
requestHandler.py
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
from simpleServer.handler import *
class RequestHandler(BaseHTTPRequestHandler):
Cases = [Case_cgi_file(),Case_directory_idnex_file(),Case_existing_file() ,]
# How to display an error.
Error_Page = """\
<html>
<body>
<h1>Error accessing {path}</h1>
<p>{msg}</p>
</body>
</html>
"""
# Classify and handle request.
def do_GET(self):
try:
# 使用join會有問題,目前還沒搞清楚+可以,join會有問題
self.full_path = os.getcwd()+self.path
# Figure out how to handle it.
print('cases{}'.format(self.Cases))
for case in self.Cases:
if case.test(self):
case.act(self)
break
# 處理異常
except Exception as msg:
print(msg)
self.handle_error(msg)
# Handle unknown objects.
def handle_error(self, msg):
content = self.Error_Page.format(path=self.path, msg=msg)
self.send_content(content.encode('utf-8'), 404)
# Send actual content.
def send_content(self, content, status=200):
self.send_response(status)
self.send_header("Content-type", "text/html")
self.send_header("Content-Length", str(len(content)))
self.end_headers()
self.wfile.write(content)
if __name__=="__main__":
severAddress=('',8000)
server=HTTPServer(severAddress,RequestHandler)
server.serve_forever()
參考附錄
1, pyton:pep-0333
2, flask作者博客文章:getting-started-with-wsgi
3, 自己寫一個 wsgi 服務器運行 Django 、Tornado 等框架應用
4, 500L:a-simple-web-server
5, python wsgi簡介
6, 從零開始搭建論壇(二):Web服務器網關接口
7, python的 WSGI 簡介
8,本文github源碼