python:记一次简单的模拟flas

发布时间:2019-09-30 07:17:38编辑:auto阅读(1887)

    最近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源码

关键字