Table of Contents

 

06WSGI

07服务器支持WSGI

08服务器传递需要的字典参数

09 框架获取页面模板数据

10 添加配置文件、shell功能


简单服务器背景知识

02面向对象服务器

需要http协议的web服务器

03动态解析

回应的时候不止直接返回header+文件

Body中返回变量的字符串-->解耦,调用web框架(负责逻辑)

04

动态的网站是实时生成的

05 将web服务器和逻辑处理分开

Web框架写完login()方法

在服务器import web_frame

Body= web_frame.login()—这一部分依然没有解耦

需要只调用一个函数

在web_frame中定义application函数

服务器将文件名传入application,用body接收返回值

Application根据文件名自己调用

06WSGI

动态请求对应框架中的函数

使用著名服务器Nginx等时,不能在已有服务器中导入自己的模块,如何使自己写的框架被服务器支持?

要根据协议(WSGI)来写框架(Flask、Django等)

WSGI规定浏览器请求内容,应返回数据:header+body

WSGI接口定义,要求开发者实现application函数,响应HTTP请求:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return '<h1>Hello, web!</h1>'

参数:environ字典,start_response函数的引用(函数名)

start_response是服务器定义的函数,可以通过这个引用调用此函数

header通过调用start_response参数传递给服务器

Body直接用return返回

07服务器支持WSGI

调用函数运走了一份header,我再return他一个body

服务器把header和body加起来

调用start_response时传入参数:1.状态码 2.元组列表,其中每个元组包括response需要的k-v(对应一行信息)

服务器取出框架通过start_response传来的headers实例属性:

for temp in self.headers:
  header+=”%s:%s\r\n” % (temp[0], temp[1])

08服务器传递需要的字典参数

框架需要告诉服务器用了什么编码语音(放在'Content-Type后面)

服务器版本:Server不应该由框架决定、传递,在服务器中加

env=dict()目前还是空字典

需要访问不同的py,返回不同页面,则使用它,接收的filename是字符串

服务器

env[‘PATH_INFO’]=file_name

框架

filename=env[‘PATH_INFO’]

09 框架获取页面模板数据

将frame文件单独放一个文件夹dynamic,新建__init__.py作为包,可被import

import dynamic.mini_frame
#调用
dynamic.mini_frame

原本框架接收application参数后只是调用对应函数返回值,现需改成页面数据:

可直接return含大段html的字符串,这时link引用的css和js还无法获取

服务器接收到. css等静态文件需要去static文件夹找

f=open(“./static”+filename,”rb”)

框架返回时读文件返回,而不要直接返回html字符串:

with open(“./templates/index.html”) as f:
content=f.read()
return content

如果打开../templates/index.html(相对路径上一级)则无法找到,因为运行的是服务器文件,所有路径都从运行py开始算,不管打开文件的代码是不是在其他包内

一般情况下,服务器和框架是分开的,框架作为可导入的包,服务器加载框架中的.py,框架读取templates中的html文件,并作为字符串返回给服务器

10 添加配置文件、shell功能

需求:能否改端口、不修改服务器支撑其他框架

给程序传参:

python3 web_server.py 7788 mini_frame:application

import sys

print(sys.argv)

接收到参数[‘’test.py,‘7788’,’ mini_frame’]是字符串,不是数字

在服务器中:

import sys
def main():
  if len(sys.argv)==3:
try:
port=int(sys.argv[1])
except Exception as ret:
  print(“端口应该为数字”)
  return
  else:
print(“运行格式:python3 xxxx.py 7890 mini_frame:application”)
return
  wsgi_server=WSGIServer(port)
  wsgi_server.run_forever()
class WSGIServer(object):
  def __init__(self,port):
    self.tcp_server_socket.bind(“”,port)

指定模块运行,原先导入了dynamic.mini_frame,但应该是通用的,故作为参数

python3 web_server.py 7788 mini_frame:application

如何找到该函数:在获取该参数后import,它把直接写的作为模块名而非变量解析,但__import__()可以放变量,返回的对象标记着导入的这个模块, 则getattr返回值指向该模块application

sys.path.append()可添加系统环境路径

frame_app_name=sys.argv[2]
re.match(r”({[^:]+}):({.*})”, frame_app_name)
#前半部分不是冒号的至少有一个
if ret:
  frame_name=ret.ret.group(1)
  app_name=ret.ret.group(1)
else:
print(“运行格式:python3 xxxx.py 7890 mini_frame:application”)
sys.path.append(“./dynamic”)
frame=__import__(frame_name)
app=getattr(frame,appn_name)
 
wsgi_server=WSGIServer(port,app)

使用时

self.application=app
body=self.application(env,self.set_response_header)

解耦不够彻底:

  1. 所有静态文件都在static文件夹打开
  2. 模块要放在./dynamic

支持配置文件:

创建web_server.conf

存储静态文件和框架加载路径

{
       "static_path":"./static",
       "synamic_path":"./dynamic"
}

在服务器中读取文件字符串,转成字典

with open("./web_server.conf") as f:
       conf_info=eval(f.read())#eval转成字典
sys.path.append(conf_info['dynamic_path'])
 
wsgi_server=WSGIServer(port,app,conf_info['static_path'])

#使用

self.static_path=static_path#init中
f=open(self.static_path+filename,"rb")

shell脚本(放Linux命令):vim run.sh

python3 web_server.py 7890 miniframe:application

添加可执行权限x:

chmod +x run.sh
./run.sh

添加readme.txt:

运行方式./run.sh或python3 web_server.py 7890 miniframe:application

version等