CRIME

导航

Python练习 | WebServer

#-*- coding:utf-8 -*-

import sys, os
from http.server import BaseHTTPRequestHandler, HTTPServer

#---------------------------------------------------------------------------------- 
class ServerException(Exception):
    '''服务器内部错误'''
    pass

#----------------------------------------------------------------------------------    
class base_case(object):
    """条件处理基类"""
        
    #从地址中读取文件送给send_content()返回请求
    def handle_file(self,hander,full_path):
        try:
            with open(full_path, 'rb') as reader:
                content = reader.read()
            hander.send_content(content)
        except IOError as msg:
            msg = "'{0}' cannot be read: {1}".format(full_path, msg)
            hander.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_no_file(base_case):
    '''文件或目录不存在'''

    def test(self, handler):
        return not os.path.exists(handler.full_path)
        #如果path存在,返回True;如果path不存在,返回False

    def act(self, handler):
        raise ServerException("'{0}' not found".format(handler.path))

#---------------------------------------------------------------------------------- 
class case_cgi_file(base_case):
    '''可执行脚本'''

    def run_cgi(self, handler):
        data = subprocess.check_output(["python3", handler.full_path],shell=False)
        handler.send_content(data)

    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)

#---------------------------------------------------------------------------------- 
class case_existing_file(base_case):
    '''该路径是文件'''

    def test(self, handler):
        return os.path.isfile(handler.full_path)
        #如果path是一个存在的文件,返回True。否则返回False

    def act(self, handler):
        self.handle_file(handler,handler.full_path)

#---------------------------------------------------------------------------------- 
class case_directory_index_file(base_case):
    '''在跟路径下返回主页文件'''
 
    #判断目标路径是否是目录&&目录下是否有index.html
    def test(self, handler):
        return os.path.isdir(handler.full_path) and \
               os.path.isfile(self.index_path(handler))
               #isdir函数判断某一路径是否为目录

    #响应index.html的内容
    def act(self, handler):
        self.handle_file(handler,self.index_path(handler))

#---------------------------------------------------------------------------------- 
class case_always_fail(object):
    '''所有情况都不符合时的默认处理类'''

    def test(self, handler):
        return True

    def act(self, handler):
        raise ServerException("Unknown object '{0}'".format(handler.path))


#一、创建一个请求处理类
#1.模块的 BaseHTTPRequestHandler类 会帮我们处理对请求的解析
#2.并通过确定请求的方法来调用其对应的函数(方法Get对应do_get方法)
#---------------------------------------------------------------------------------- 
#RequestHandler 继承了 BaseHTTPRequestHandler 并重写了 do_GET 方法
class RequestHandler(BaseHTTPRequestHandler):
    '''
    请求路径合法则返回相应处理
    否则返回错误页面
    '''
    Cases = [case_no_file(),
             case_cgi_file(),
             case_existing_file(),
             case_directory_index_file(),
             case_always_fail()]

    # 错误页面模板
    Error_Page = """\
        <html>
        <body>
        <h1>Error accessing {path}</h1>
        <p>{msg}</p>
        </body>
        </html>
        """

    def do_GET(self):
        try:
            #得到完整的请求路径
            #os.getcwd()返回当前进程的工作目录
            #BaseHTTPRequestHandler类使请求的相对路径保存在self.path
            self.full_path = os.getcwd() + self.path                                    

            # 遍历所有的情况并处理
            for case in self.Cases:
                if case.test(self):
                    case.act(self)
                    break

        # 处理异常
        except Exception as msg:
            self.handle_error(msg)

    #错误处理函数
    def handle_error(self, msg):
        content = self.Error_Page.format(path=self.path, msg=msg)
        self.send_content(content.encode("utf-8"),404)  #content内容被编码为二进制

    # 发送数据到客户端
    def send_content(self,content, status=200):
        self.send_response(status)
        self.send_header("Content-Type", "text/html")    #Content-Type 告诉客户端要以处理html文件的方式处理返回的内容
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()     #end_headers 方法会插入一个空白行
        self.wfile.write(content)

#主函数
if __name__ == '__main__':
    serverAddress = ('', 8080)
#二、实例化一个服务器类,传入服务器的地址和请求处理程序类
    server = HTTPServer(serverAddress, RequestHandler)
#三、调用handle_request()(一般是调用其他事件循环或者使用select())或serve_forever()
    server.serve_forever()

posted on 2019-04-29 15:57  CRIME  阅读(164)  评论(0)    收藏  举报