python:記一次簡單的模擬flask和cgi服務器

最近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.pyhtml

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.pypython

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源碼git

相關文章
相關標籤/搜索