web框架解析

1、白手起家

  要想模拟出web请求响应的流程,先想一想平时咱们是怎么上网浏览网页的?首先打开浏览器,而后在地址栏中输入咱们想要访问的页面,紧接着按下回车键Enter,最后跳转至目标页面(固然咱们也会出现访问失败的状况,暂时不讨论这种状况,之后另作讲解)。python

  总结一下咱们能够将此流程分解为下面几步:web

  1. 浏览器发送一个HTTP请求;
  2. 服务器收到请求,生成一个HTML文档;
  3. 服务器把HTML文档做为HTTP响应的Body发送给浏览器;
  4. 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

  发送请求和响应请求其实就是基于socket套接字的网络通讯,那咱们如何获得用户请求访问的路径呢?浏览器

  这是以前提到的HTTP get请求的数据格式服务器

  咱们能够看到在请求行内有用户想要访问的页面路径URL,能够经过字符串的分割得到:网络

  1. 将请求bytes转成字符串(decode)
  2. 用split方法按/r/n切,取列表的第一个元素,即取到请求首行
  3. 再按空格切,取第二元素获得URL,即用户访问的页面路径。

  以后咱们能够根据用户想要访问的URL返回不一样的信息给他,这样一看非常艰辛,但事实上对于真实开发中的python web程序来讲,通常会分为两部分:服务器程序和应用程序。框架

  服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各类数据进行整理。socket

  应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask等。不一样的框架有不一样的开发方式,可是不管如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。函数

  这样,服务器程序就须要为不一样的框架提供不一样的支持。这样混乱的局面不管对于服务器仍是框架,都是很差的。对服务器来讲,须要支持各类不一样框架,对框架来讲,只有支持它的服务器才能被开发出的应用使用。编码

  这时候,标准化就变得尤其重要。咱们能够设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就能够配合使用。一旦标准肯定,双方各自实现。这样,服务器能够支持更多支持标准的框架,框架也可使用更多支持标准的服务器,WSGI应运而生。url

2、WSGI

  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框架的模式,以后会详细说明。

相关文章
相关标签/搜索