Web框架的本质

对于学习Python的同学,相信对Flask、Django、Web.py等不会陌生,这些都是Python语言的web框架。那么问题来了,web服务器是什么?它和web框架有什么关系?它们又是如何工作的?有的时候人们会把HTTP服务器叫做web服务器,这是为什么?我们今天就来聊聊这些,争取让大家对web开发有个清晰的认识。

web服务器

平时我们都是通过浏览器(Chrome、Firefox)来访问网站的,当我们在浏览器的地址栏输入地址后,会得到一个网页。这个网页就是web服务器返回给我们的,而浏览器就成为客户端,当我们输入网址并按下回车之后,就向web服务器发送了一个web请求。这种模式称为B/S模式,即Brower / Server模式,在浏览器地址栏输入地址按回车后,按下F12就可以看到如下信息:

这整个过程如下图所示:

  • 建立连接:客户端通过TCP/IP协议建立到服务器的TCP连接;
  • 请求过程:客户端向服务器发送HTTP协议请求包(Request),请求服务器里的资源;
  • 应答过程:服务器向客户端发送HTTP协议应答包(Response),如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理"动态内容",并将处理的得到的数据返回给客户端。由客户端解释HTML文档,在客户端屏幕上渲染图形结果;
  • 关闭连接:客户机与服务器断开;

这里Request和Response都需要遵守HTTP协议,关于HTTP协议的详细内容,并不在这里赘述。但是实际的web服务器远比上面的示例复杂的多,因为要考虑的因素实在太多了,比如:

  • 缓存机制:将某些经常被访问的页面缓存起来,提高响应速度;
  • 安全:防止黑客攻击,比如SYN Flood攻击;
  • 并发处理:如何响应不同客户端同时发起的请求;
  • 日志:记录访问日志,方便问题分析处理;

目前在Linux和Unix平台下使用最广泛的免费web服务器有Apache和Nginx,而这些软件都是遵循HTPP协议的,所以也称为HTTP服务器,指示可以通过HTTP协议语言的解析转换。

web应用程序

web服务器接收Http Request,返回Response,很多时候Response并不是静态文件,因此需要有个应用程序根据Request生成相应的Response。这里的应用程序主要用来处理相关业务逻辑,读取或者更新数控,根据不同Request返回相应的Response。注意这里并不是web服务器本身来做这件事,它只负责Http协议层面和一些诸如并发处理、安全、日志等相关的事情。应用程序可以用各种语言编写(Java,PHP,Python,Ruby)等,这个应用程序会从web服务器接收客户端的请求,处理完成后,再返回响应给web服务器,最后由web服务器返回给客户端。整个架构如下所示:

对于所有的web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端

web框架(Framework)

框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮助我们快速开发特定的系统,简单的说,就是利用别人搭建好的舞台来做表演。以Python web框架Flask为例,框架本身并不限制我们使用哪种架构来组织我们的应用,不过其中一种比较经典的web框架Flask采用了MVC架构,可以很好地支持以MVC方式组织应用:

  • 1.用户输入URL,客户端发送请求;
  • 2.控制器(Controller)首先拿到请求;
  • 3.然后用模型(Models)从数据库中取出所有需要的数据,进行必要的处理,将处理后的结果发送给视图(View);
  • 4.视图利用获取到的数据,进行渲染生成Html Response返回给客户端;

具体如下图所示:

还有一种同样热门且强大的web框架:Django,它的模式是MTV。Django的MTV模式本质是各组件之间为了保持松耦合关系,其MTV分别代表:

  • Model(模型):负责业务对象与数据库的对象(ORM);
  • Template(模板):负责如何把页面呈现给客户;
  • View(视图):负责业务逻辑,并在适当的时候调用Model和Template;

此外,Django还有一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template。

Web服务器网关接口

我们知道Python有着许多的Web框架,而同时又有着许多的Web服务器(Apache,Nginx,Gunicorn等),框架和Web服务器之间需要进行通信,如果在设计时它们之间不可以相互匹配,那么选择了一个框架就会限制对Web服务器的选择,同样选择了Web服务器也会限制对Web框架的选择,这显然是不合理的。

那么,怎样确保可以在不修改Web服务器代码或Web框架代码的前提下,使用自己选择的服务器,并且匹配多个不同的Web框架呢?答案是:接口,设计一套双方都遵守的接口就可以了。对Python来讲,就是WSGI(Web Server Gateway Interface,Web服务器网关接口)。其他编程语言也拥有类似的接口:例如Java的Serverlet API和Ruby的Rack。

Python WSGI的出现,让开发者可以将Web框架与Web服务器的选择分隔开来,不再相互限制。现在我们可以真正地将不同的Web服务器与Web框架进行混合搭配,选择满足自己需求的组合。例如,可以使用Gunicorn或Nginx/uWSGI来运行Django、Flask或web.py应用。

总结

Web Server包括:

  • 提供Http服务的软件(Nginx);
  • Web应用程序在这个层面有许多Web框架Django、Flask、Tornado等;
  • 后端存储数据库Redis、MySQL等;

自定义Web框架

1.通过Python标准库提供的wsgiref模板开发一个自己的Web框架(Python3):

from wsgiref.simple_server import make_server

def index():
return [bytes("<h2>index</h2>", encoding="utf-8"), ] def login():
return [bytes("<h2>login</h2>", encoding="utf-8"), ] def routers():
urlpatterns = (
("/index/", index),
("/login/", login),
)
return urlpatterns def run_server(environ, start_response):
start_response("200 OK", [("Content-Type", "text/html")])
url = environ["PATH_INFO"]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ] if __name__ == "__main__":
httpd = make_server("", 8000, run_server)
print("Servering HTTP on port 8000....")
httpd.serve_forever()

2.模板引擎

在上步中,对于所有的login、index均返回给用户浏览器要给简单的字符串,在现实的Web请求中一般会返回一个复杂的符合HTML规则的字符串,所以我们一般将要返回给用户的HTML写在指定文件中,然后再返回。如:

<!DOCTYPE html>         <!-- html文件声明开始 -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<!-- index.html -->
<h1>Index</h1>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<!-- login.html -->
<form>
<input type="text" />
<input type="button" />
<input type="submit" />
</form>
</body>
</html>

根据模板,将框架代码进行如下修改:

from wsgiref.simple_server import make_server

def index():
# return [bytes("<h2>index</h2>", encoding="utf-8"), ]
index = open("index.html")
data = index.read()
return data def login():
# return [bytes("<h2>login</h2>", encoding="utf-8"), ]
login = open("login.html")
data = login.read()
return data def routers():
urlpatterns = (
("/index/", index),
("/login/", login),
)
return urlpatterns def run_server(environ, start_response):
start_response("200 OK", [("Content-Type", "text/html")])
url = environ["PATH_INFO"]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ] if __name__ == "__main__":
httpd = make_server("", 8000, run_server)
print("Servering HTTP on port 8000....")
httpd.serve_forever()

对于上述代码,虽然可以返回给用户HTML的内容以实现复杂的页面,但是还是存在问题:如何给用户动态内容?

  • 自定义一套特殊的语法,进行替换;
  • 使用开源工具Jinja2,遵循其指定语法;
<!DOCTYPE html>         <!-- html文件声明开始 -->
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 文件体 -->
<h1>{{name}}</h1>
<ul>
{% for item in user_list %}
<li>{{item}}</li>
{% endfor %}
</ul>
</body>
</html>
from wsgiref.simple_server import make_server
from jinja2 import Template def index():
# return [bytes("<h2>index</h2>", encoding="utf-8"), ]
index = open("index.html")
data = index.read()
template = Template(data)
resutlt = template.render(name="Bob Gates", user_list=["eric", "rose"])
return resutlt.encode("utf-8") def login():
# return [bytes("<h2>login</h2>", encoding="utf-8"), ]
login = open("login.html")
data = login.read()
return data def routers():
urlpatterns = (
("/index/", index),
("/login/", login),
)
return urlpatterns def run_server(environ, start_response):
start_response("200 OK", [("Content-Type", "text/html")])
url = environ["PATH_INFO"]
urlpatterns = routers()
func = None
for item in urlpatterns:
if item[0] == url:
func = item[1]
break
if func:
return func()
else:
return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ] if __name__ == "__main__":
httpd = make_server("", 8000, run_server)
print("Servering HTTP on port 8000....")
httpd.serve_forever()

遵循Jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容。

Django 2.0 学习(15):Web框架的更多相关文章

  1. Spark2.1.0——内置Web框架详解

    Spark2.1.0——内置Web框架详解 任何系统都需要提供监控功能,否则在运行期间发生一些异常时,我们将会束手无策.也许有人说,可以增加日志来解决这个问题.日志只能解决你的程序逻辑在运行期的监控, ...

  2. Django 2.0 学习(07):Django 视图(进阶-续)

    接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...

  3. Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基础文件配置,Web框架的本质,服务器程序和应用程序(wsgiref服务端模块,jinja2模板渲染模块)的使用

    Django---Http协议简述和原理,HTTP请求码,HTTP请求格式和响应格式(重点),Django的安装与使用,Django项目的创建和运行(cmd和pycharm两种模式),Django的基 ...

  4. Django:之不得不说的web框架们

    python的web框架 Bottle Bpttle是一个快速.简洁.轻量级的基于WSIG的微型web框架,此框架只有一个.py文件,除了python的标准库外,其不依赖任何其它模块. pip ins ...

  5. 通过Django Channels设计聊天机器人WEB框架

    这两个月都在忙着设计针对银联客服业务的智能聊天机器人,上一周已经交完设计报告,这一周还和部门同事一起分享了系统设计及运行效果.因为时间的关系,系统原型我使用了Flask+jQuery的组合,感觉用以原 ...

  6. 详说Flask、Django、Pyramid三大主流 Web 框架

    前言 目前随着 Python 在大数据.云计算.人工智能方面的热度,Python Web 应该也会被更多企业了解使用. Python Web 框架千万种,没必要都去了解和学习,身边总有人说高手都用 F ...

  7. Python学习-day18 Web框架

    众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 ...

  8. Django 2.0 学习

    Django django是基于MTV结构的WEB框架 Model 数据库操作 Template 模版文件 View 业务处理 在Python中安装django 2.0 1 直接安装 pip inst ...

  9. Django 2.0 学习(01):Django初识与安装

    Django(Python Web框架) Django是一个开放源代码的Web框架,用Python写的.采用了MTV的框架模式,即模型M,模板T和视图V.它最初被开发是用来管理以新闻内容为主的网站,即 ...

随机推荐

  1. 20155338 《Java程序设计》实验一(Java开发环境的熟悉)实验报告

    20155338 <Java程序设计>实验一(Java开发环境的熟悉)实验报告 一.实验内容及步骤 1.用JDK编译.运行简单的java程序 步骤一(新建文件夹): 打开windows下的 ...

  2. 深度学习开源库tiny-dnn的使用(MNIST)

    tiny-dnn是一个基于DNN的深度学习开源库,它的License是BSD 3-Clause.之前名字是tiny-cnn是基于CNN的,tiny-dnn与tiny-cnn相关又增加了些新层.此开源库 ...

  3. cookie和session在Django中的应用

    1 会话跟踪技术 什么是会话跟踪 我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应.例如你给10086打个电话,你就是客户端,而1008 ...

  4. javaweb(三十八)——mysql事务和锁InnoDB(扩展)

    MySQL/InnoDB的加锁分析,一直是一个比较困难的话题.我在工作过程中,经常会有同事咨询这方面的问题.同时,微博上也经常会收到MySQL锁相关的私信,让我帮助解决一些死锁的问题.本文,准备就My ...

  5. Android Studio 3.1.2 Device File Explorer nothing to show

    Android Studio 3.1.2 Device File Explorer nothing to  show 不显示 目录  ,空白 手持终端设备: Android  4.2.2  ,API1 ...

  6. My status

    I haven‘t any one who is strong relationship with me. My skill is normal. I'm not interesting in neg ...

  7. Centos7.2部署saltstack

    原文发表于cu:2016-06-23 参考文档: Saltstack安装文档:https://repo.saltstack.com/#rhel saltstack的安装与简单配置,应用. 一.环境 S ...

  8. MongoDB Chapter1:Introduction

    你是在防火墙后面吗? 为了继续本课程,您必须能够将计算机的传出请求发送到我们在MongoDB Atlas中设置的数据库服务器.这些服务器在Amazon AWS中的端口27017上运行. 请单击http ...

  9. Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法

    Linux系统中,进程之间有一个明显的继承关系,所有进程都是 PID 为1的 init 进程的后代.内核在系统启动的最后阶段启动 init 进程.该进程读取系统的初始化脚本(initscript)并执 ...

  10. presto——java.sql.SQLException: Error executing query与javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?异常问题

    使用presto的时候以mysql为presto的数据源 安装的presto是0.95版本:使用的presto-jdbc是0.202的,这里使用jdbc去访问时候,connection可以链接成功,但 ...