MENU

仿flask的简易web框架

• March 30, 2019 • Read: 139 • python

最近刷了一遍传播智客的python视频,总算入了门。作为结课证明,把最后的项目撸了一遍,加深记忆。

之前发过一次自己动手撸的web服务器,本次使用的还是之前撸的多线程版本的,不过修改了一下,使之支持WSGI协议。然后用到的前端文件,是传播智科老师提供的。用到的前端模板和数据库我在文章最后分享一下吧。

我把撸好以后的放在我的腾讯云小鸡儿上跑了一下,勉强能看2333.
地址:111.231.102.149:20000/index.html

贴一下代码:

web_server.py

import socket
import threading
import re
from dynamic.mini_frame import application

class WSGIServer(object):

    def __init__(self,server_addr):
        #建立一个socket对象
        self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        #设置socket选项
        #https://www.jb51.net/article/50858.htm
        self.tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

        #绑定端口
        self.tcp_server_socket.bind(server_addr)

        # 变成被动,开始监听
        self.tcp_server_socket.listen(128)

    def set_response(self,status,response_headers):
        self.header='HTTP/1.1 %s \n ' % str(status)
        for item in response_headers:
            self.header+=item[0]+':'+item[1]+'\n'
        print(self.header)


    # 请求处理函数
    def request_handle(self,client_socket):
        recv_data = client_socket.recv(1024).decode('utf8')

        #获取请求信息的第一行
        #http://www.runoob.com/python/att-string-splitlines.html
        first_line=recv_data.splitlines()[0]
        print(first_line)

        #提取要请求的资源地址
        #http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html
        file_name = re.match(r"^[A-Za-z\s]+(/[^ ]*)",str(first_line))
        file_name=file_name.group(1)
        print(file_name)

        if not file_name.endswith('.html'):
            try:
                file_name='.'+file_name
                with open(file=file_name, mode='rb') as f:
                    content = f.read().decode('utf8')
                response_header = 'HTTP/1.1 200 OK ' + '\n' + 'Content-Length:%d' % len(content) + '\n\n'
            except:
                content = "-" * 20 + "404  FILE NOT FOUND" + '-' * 20
                response_header = 'HTTP/1.1 404 FILE NOT FOUND' + '\n' + '\n'
            client_socket.send((response_header + '\n' + content).encode('utf8'))
        else :

            environ_dict=dict()
            #构建发送给框架的请求头信息
            environ_dict['FILE_PATH']=file_name
            body=application(environ_dict,self.set_response)

            # 返回给浏览器客户端响应体
            client_socket.send((self.header+'\n'+body).encode('utf8'))
        client_socket.close()

    #监听循环
    def server_loop(self):
        while True:
            #监听来自客户端的连接
            client_socket,clent_addr=self.tcp_server_socket.accept()

            #创建一个新的线程处理客户端请求
            t=threading.Thread(target=self.request_handle,args=(client_socket,))
            t.start()
        #self.tcp_server_socket.close()

def main():
    wsgi_server=WSGIServer(('',20000))
    wsgi_server.server_loop()

if __name__ == '__main__':
    main()

mini_frame.py

from pymysql import *
import re
import urllib.parse
FUNC_DICT=dict()
def route(url):
    #print('最外层函数被调用')
    def return_func(func):
        FUNC_DICT[url] = func
        print('函数加载进列表')
        def set_func_dict(file_name):
            #FUNC_DICT[url]=func
            func()
        return set_func_dict
    return return_func

@route('/index.html')
def index(file_name='/index.html'):
    try:
        file_name = './templates' + file_name
        with open(file=file_name, mode='rb') as f:
            content = f.read().decode('utf8')
        conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849', charset='utf8')
        cs = conn.cursor()
        sql='select * from info;'
        count=cs.execute(sql)
        #print(count)
        result=cs.fetchall()
        conn.commit()
        cs.close()
        conn.close()
        #print(result)
        tr_template = """<tr>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>
                    <input type="button" value="添加" id="toAdd" name="toAdd" systemidvaule="%s">
                </td>
                </tr>
            """
        html=""
        for item in result:
            html+=tr_template % (item[0],item[1],item[2],item[3],item[4],item[5],item[6],item[7],item[1])
        #print(tr_template)
        #正则表达式中需要被转义的特殊字符https://blog.csdn.net/kanglong129/article/details/80689195
        content=re.sub(r'\{%content%\}',html,content)
    except:
        content = "-" * 20 + "404  FILE NOT FOUND" + '-' * 20
    return content

@route('/center.html')
def center(file_name):
    try:
        file_name = './templates' + file_name
        with open(file=file_name, mode='rb') as f:
            content = f.read().decode('utf8')
        conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849',charset='utf8')
        cs = conn.cursor()
        sql = 'select * from info inner join focus on  info.id= focus.info_id;'
        count = cs.execute(sql)
        #print(count)
        result = cs.fetchall()
        conn.commit()
        cs.close()
        conn.close()
        #print(result)
        tr_template = """
            <tr>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>%s</td>
                <td>
                    <a type="button" class="btn btn-default btn-xs" href="/update/%s.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>
                </td>
                <td>
                    <input type="button" value="删除" id="toDel" name="toDel" systemidvaule="%s">
                </td>
            </tr>
        """
        html = ""
        for item in result:
            html += tr_template % (item[1], item[2], item[3], item[4], item[5], item[6], item[9], item[1], item[0])
        #print(tr_template)
        # 正则表达式中需要被转义的特殊字符https://blog.csdn.net/kanglong129/article/details/80689195
        content = re.sub(r'\{%content%\}', html, content)
    except:
        content = "-" * 20 + "404  FILE NOT FOUND" + '-' * 20
    return content

@route(r'/add')
def add(file_name):
    info_id = re.match(r'/add/(\d+).html', file_name).group(1)
    print("info_id:"+info_id)
    conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849', charset='utf8')
    cs = conn.cursor()
    select_sql = 'select * from info where code = %s' % info_id
    count = cs.execute(select_sql)
    print(type(count))
    if count != 0:
        result = str(cs.fetchone()[0])
        select_focus_sql='select * from focus where info_id =%s' % result
        response=cs.execute(select_focus_sql)
        if response == 0:
            sql = 'insert into focus values(0,"",%s);' % result
            count = cs.execute(sql)
    conn.commit()
    cs.close()
    conn.close()
    return '添加成功'

@route(r'/del')
def del_from_sql(file_name):
    info_id = re.match(r'/del/(\d+).html', file_name).group(1)
    conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849', charset='utf8')
    cs = conn.cursor()
    sql = 'delete from focus where info_id=%s;' % info_id
    count = cs.execute(sql)
    result = cs.fetchall()
    conn.commit()
    cs.close()
    conn.close()
    return "删除成功"

@route(r'/update')
def sql_update(file_name):
    #try:
    print(file_name)
    file_name_return = './templates' + '/update.html'
    with open(file=file_name_return, mode='rb') as f:
        content = f.read().decode('utf8')
    if re.match(r'/update/(\d+).html', file_name)!=None:
        conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849',charset='utf8')
        cs = conn.cursor()
        code = re.match(r'/update/(\d+).html', file_name).group(1)
        sql = 'select * from info where code =%s;' % code
        cs.execute(sql)
        result = cs.fetchall()[0][2]
        print(result)
        #update_sql='update focus set note_info= where 条件;'
        content = re.sub(r'\{%code%\}', result, content)
        content = re.sub(r'\{%note_info%\}', "请输入内容", content)
        conn.commit()
        cs.close()
        conn.close()
        return content
    elif re.match(r'/update/(.+)/(.+).html',file_name)!=None:
        print('_'*30)
        conn = connect(host='39.96.1.252', port=3306, database='stock_db', user='root', password='137849',charset='utf8')
        cs = conn.cursor()
        data=re.match(r'/update/(.+)/(.+).html',file_name)
        short=data.group(1)
        post_text=data.group(2)
        sql = 'select * from info where short ="%s";' % urllib.parse.unquote(short)
        count = cs.execute(sql)
        result = cs.fetchall()[0][0]
        sql = 'update focus set note_info="%s" where info_id=%s' % (urllib.parse.unquote(post_text), result)
        cs.execute(sql)
        conn.commit()
        cs.close()
        conn.close()
        return "操作成功"
    else:
        return "-" * 20 + "404  FILE NOT FOUND" + '-' * 20

#实现WSGI接口
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    re_result=re.match( r'/add/(\d+).html',environ['FILE_PATH'])
    if re_result:
        FUNC_DICT[environ['FILE_PATH']]=FUNC_DICT[r'/add']
    if re.match( r'/del/(\d+).html',environ['FILE_PATH']):
        FUNC_DICT[environ['FILE_PATH']]=FUNC_DICT[r'/del']
    if re.match( r'/update/(.+).html',environ['FILE_PATH']):
        FUNC_DICT[environ['FILE_PATH']]=FUNC_DICT[r'/update']

    if environ['FILE_PATH'] in FUNC_DICT:
        return FUNC_DICT[environ['FILE_PATH']](environ['FILE_PATH'])
    else:
        return  "-" * 20 + "404  FILE NOT FOUND" + '-' * 20

用到的知识还是蛮多的,真“面向百度”编程,全程都在百度2333。数据库的密码的ip地址我没打码,数据库里也没啥重要东西,老哥们就别捣乱了2333。

框架及前端文件链接:https://share.weiyun.com/5cgRCJG

数据库备份链接:https://share.weiyun.com/5frH9Um

Tags: python
Archives QR Code Tip
QR Code for this page
Tipping QR Code
Leave a Comment