首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >python之动态web服务器-WSGI协议

python之动态web服务器-WSGI协议

作者头像
用户8639654
修改2021-08-19 18:06:03
修改2021-08-19 18:06:03
1.2K0
举报
文章被收录于专栏:云计算运维云计算运维

已经知道怎么让服务器返回静态的网页了,但是还是不能满足需求,网页数据要是能变化的才好,这样我想要的数据才是最新的。

于是就有了WSGI协议(Web Server Gateway Interface),前面我们的调用的只是静态的文件,要是想让网页数据随时变化,就需要引入可执行的代码,即脚本。WSGI协议就提供了这样一个接口,可以根据客户端的请求,调用py文件。WSGI接口接收两个参数:

env:一个包含所有HTTP请求信息的 。(是一个字典)

start_response:一个发送HTTP响应的函数。 (就是客户端要的信息,动态的)

还是一步一步来实现吧:(与返回静态网页不一样的地方只是如果接受到的请求信息是py文件,就调用函数,返回响应信息,其他都是一样的。

一,创建套接字。

现在我开始学着用面向对象的编程思想去处理问题了,所以创建套接字,可以直接在类的属性里创建。

代码语言:javascript
复制
class Recvsocket(object):
    def __init__(self):
        self.server = socket(AF_INET, SOCK_STREAM)
        self.server.bind(("", 7788))
        self.server.listen(5)

第二步,等待接收客户端请求,返回新的套接字。

代码语言:javascript
复制
    def recvsocket(self):
        while True:
            self.client_socket, ip_port = self.server.accept()
            print("%s:%s>>>正在连接中。。。" % ip_port)
            childthread = Thread(target=self.newsocket, args=(self.client_socket,))
            childthread.start()

第三步,新的套接字处理客户端请求。(最重要的部分)

代码语言:javascript
复制
    def newsocket(self , client_socket):
        recvdata = self.client_socket.recv(1024)
        print("request data:", recvdata)
        recv_lines = recvdata.splitlines()
        request_start_line = recv_lines[0]
        file_name = re.match(r"\w+ +(/[^ ]*) ", request_start_line.decode("utf-8")).group(1)
        if file_name.endswith(".py"):
            m = __import__(file_name[1:-3])        #1,这是最重要的一步,检测到py文件,提取出文件名,导入模块
            env = {}
            response_boby = m.application(env , self.start_response) #,2,这是很重要一步,调用导入模块的函数,并得m_time的结果
            response = self.response_header + "\r\n" + response_boby   #动态文件的响应报文
        else:
            if "/" == file_name:    #如果不是py结尾的请求,就返回静态文件
                file_name = "/index.html"
            try:
                file = open(HTML_ROOT_DIR + file_name , "rb")
            except IOError:
                self.response_start_line = "HTTP/1.1 404 Not Foud\r\n"
                self.response_headers = "Server: pycharm server\r\n"
                self.response_boby = "The file is not fund!"
            else:
                file_data = file.read()
                file.close()
                self.response_start_line = "HTTP/1.1 200 OK\r\n"
                self.response_headers = "Server: pycharm server\r\n"
                self.response_boby = file_data.decode("utf-8")
            response = self.response_start_line + self.response_headers + "\r\n" + self.response_boby  #静态文件的响应报文
        print("response data:", response)    #不管是静态页面还是动态的,都要返回,与第一个if条件平行
        client_socket.send(response.encode("utf-8"))
        client_socket.close()

第四步,在上面的函数体中导入了一个模块并引用了该模块的函数,所以我们需要单独创建一个py文件。

代码语言:javascript
复制
#coding = utf-8
import time
def application(env,start_response):
    status = "200 OK"
    server_headers = [
        ("server", "pycharm server")
    ]
    start_response(status,server_headers)    #这也是很重要的一步,返回服务器函数
    return time.ctime()

第五步,查漏补缺,缺什么补什么

代码语言:javascript
复制
from socket import *
from threading import Thread
import re
import sys
HTML_ROOT_DIR = "./html"    #指定静态文件路径
WSGI_PYTHON_DIR = "./wsgipython"            #指定动态文件路径
sys.path.insert(1 , WSGI_PYTHON_DIR)        #添加详细路径

总结WSGI协议究竟做了什么:

1,拿到客户端的请求信息,先将响应状态码和响应头返回给服务器。

(第四步中通过调用start_response函数,将两个参数传回服务器)

2,然后将响应体返回给服务器。(第四步中执行完start_response函数,然后返回time.ctime()结果给服务器的response_boby)

3.至于完整的响应报文,在服务器中拼接完成,不在导入的木块中定义。

完整的代码:

服务器的代码:

代码语言:javascript
复制
#coding = utf-8
from socket import *
from threading import Thread
import re
import sys
HTML_ROOT_DIR = "./html"
WSGI_PYTHON_DIR = "./wsgipython"
sys.path.insert(1 , WSGI_PYTHON_DIR)

class Recvsocket(object):
    def __init__(self):
        self.server = socket(AF_INET, SOCK_STREAM)
        self.server.bind(("", 7788))
        self.server.listen(5)

    def recvsocket(self):
        while True:
            self.client_socket, ip_port = self.server.accept()
            print("%s:%s>>>正在连接中。。。" % ip_port)
            childthread = Thread(target=self.newsocket, args=(self.client_socket,))
            childthread.start()

    def start_response(self,status,server_headers):
        response_header = "HTTP/1.1 " + status + "\r\n"
        for header in server_headers:
            response_header += "%s:%s\r\n"%header
        self.response_header = response_header

    def newsocket(self , client_socket):
        recvdata = self.client_socket.recv(1024)
        print("request data:", recvdata)
        recv_lines = recvdata.splitlines()
        request_start_line = recv_lines[0]
        file_name = re.match(r"\w+ +(/[^ ]*) ", request_start_line.decode("utf-8")).group(1)
        if file_name.endswith(".py"):
            m = __import__(file_name[1:-3])        #1,这是最重要的一步,检测到py文件,提取出文件名,导入模块
            env = {}
            response_boby = m.application(env , self.start_response) #,2,这是很重要一步,调用导入模块的函数,并得m_time的结果
            response = self.response_header + "\r\n" + response_boby
        else:
            if "/" == file_name:
                file_name = "/index.html"
            try:
                file = open(HTML_ROOT_DIR + file_name , "rb")
            except IOError:
                self.response_start_line = "HTTP/1.1 404 Not Foud\r\n"
                self.response_headers = "Server: pycharm server\r\n"
                self.response_boby = "The file is not fund!"
            else:
                file_data = file.read()
                file.close()
                self.response_start_line = "HTTP/1.1 200 OK\r\n"
                self.response_headers = "Server: pycharm server\r\n"
                self.response_boby = file_data.decode("utf-8")
            response = self.response_start_line + self.response_headers + "\r\n" + self.response_boby
        print("response data:", response)    #不管是静态页面还是动态的,都要返回,与第一个if条件平行
        client_socket.send(response.encode("utf-8"))
        client_socket.close()


if __name__ == '__main__':
    test = Recvsocket()
    test.recvsocket()

导入的模块代码:

代码语言:javascript
复制
#coding = utf-8
import time
def application(env,start_response):
    status = "200 OK"
    server_headers = [
        ("server", "pycharm server")
    ]
    start_response(status,server_headers)    #这也是很重要的一步,返回服务器函数
    return time.ctime()

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档