要想模拟出web请求响应的流程,先想一想平时咱们是怎么上网浏览网页的?首先打开浏览器,而后在地址栏中输入咱们想要访问的页面,紧接着按下回车键Enter,最后跳转至目标页面(固然咱们也会出现访问失败的状况,暂时不讨论这种状况,之后另作讲解)。python
总结一下咱们能够将此流程分解为下面几步:web
发送请求和响应请求其实就是基于socket套接字的网络通讯,那咱们如何获得用户请求访问的路径呢?浏览器
这是以前提到的HTTP get请求的数据格式服务器
咱们能够看到在请求行内有用户想要访问的页面路径URL,能够经过字符串的分割得到:网络
以后咱们能够根据用户想要访问的URL返回不一样的信息给他,这样一看非常艰辛,但事实上对于真实开发中的python web程序来讲,通常会分为两部分:服务器程序和应用程序。框架
服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各类数据进行整理。socket
应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask等。不一样的框架有不一样的开发方式,可是不管如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。函数
这样,服务器程序就须要为不一样的框架提供不一样的支持。这样混乱的局面不管对于服务器仍是框架,都是很差的。对服务器来讲,须要支持各类不一样框架,对框架来讲,只有支持它的服务器才能被开发出的应用使用。编码
这时候,标准化就变得尤其重要。咱们能够设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就能够配合使用。一旦标准肯定,双方各自实现。这样,服务器能够支持更多支持标准的框架,框架也可使用更多支持标准的服务器,WSGI应运而生。url
WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
经常使用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来作服务器。
有了WSGI咱们不须要接触到TCP链接、HTTP原始请求和响应格式等底层代码,咱们能够用Python专一编写web业务。下面是利用wsgiref模块编写的简易web框架
from wsgiref.simple_server import make_server from urls import * def run(env,response): """ :param env: 请求相关的信息 :param response: 响应相关的信息 :return: """ print(env) # 是一个大字典 里面装了一堆处理好了的键值对数据 response('200 OK',[('username','jason'),('password','123')]) # 固定写法 后面列表里面一个个元祖会以响应头kv键值对的形式返回给客户端 # 获取用户访问的路径 current_path = env.get('PATH_INFO') if current_path == '/index': return [b'index'] elif current_path == '/login': return [b'login'] return [b'hello] if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
固然咱们还能略微升华代码,能够看到在判断用户访问路径的时候,过多的if判断会显得整个代码冗长累赘,可读性差,因此咱们要拆分代码。定义一个字典来对应函数功能。
from wsgiref.simple_server import make_server from urls import * def index(env): return 'index' def login(env): return 'login' def error(env): return '404 error' urls = { ('/index',index), ('/login',login), } def run(env,response): """ :param env: 请求相关的信息 :param response: 响应相关的信息 :return: """ print(env) # 是一个大字典 里面装了一堆处理好了的键值对数据 response('200 OK',[('username','jason'),('password','123')]) # 固定写法 后面列表里面一个个元祖会以响应头kv键值对的形式返回给客户端 # 获取用户访问的路径 current_path = env.get('PATH_INFO') func = None # 循环比对路由与试图函数的映射关系 for url_map in urls: # url_map = ('/index',index) if current_path == url_map[0]: func = url_map[1] # 只要匹配成功 直接结束循环 break if func: res = func(env) else: res = error(env) return [res.encode('utf-8')] # 最后再统一编码 if __name__ == '__main__': server = make_server('127.0.0.1',8080,run) server.serve_forever()
固然这也不是最优方案,最终咱们能够将视图函数归于一个文件views.py,映射关系归于另外一个文件urls.py。这样当咱们须要增长用户路径的时候只须要在urls.py中添一条对应关系,在views.py中定义函数功能便可,实现了解耦合操做。哈哈,这已经稍微剧透成型的web框架的模式,以后会详细说明。