[系列教程]Web框架如何快速入门

Web框架正如前文所述, 在整个项目结构中处于一个承上启下的位置, 是整个项目的核心组件, 所以这次来聊聊Web框架的一些普适性特性和如何快速的入门.

为什么Web框架需要快速入门?

Web框架是一组工具的集合, 为你的Web应用开发提供了基础环境, 从如何获取参数, 到如何返回结果, 从如何获取cookie到如何修改返回的http header. Web框架帮你隐藏了HTTP协议的细节, 你作为一个使用者只需要关心如何使用, 而毋须去了解细节( 当然如果你打算自己实现一个Web框架除外 ).

第二个原因是Web框架很多, 不同的语言都有自己实现的不同的Web框架(Python尤其的多). 每一种都有各自不同的实现思路, 有不同的开发哲学, 不管是就换工作换开发栈的需要, 还是学习本身的需要, 快速的多掌握几个框架还是很有必要的.

继续阅读本文需要掌握HTTP协议的基本知识, 如果不了解请前往 <关于HTTP协议,一篇就够了>

以下是一个Web框架的通用Guide, 基本上你能涉及到的大多数Web框架都是遵循下面的模式来的, 少数奇葩不在本文描述的范畴, 但是需要理解的知识点和问题领域是大致相同, 你可以参考着来.

一. Web框架的工作方式

现代的Web框架,不管其采用何种设计思想, 开发哲学, 根本的工作模式是相似的,均是从接收HTTP请求,处理HTTP的各项参数,路由到相应的用户实现的处理器上, 再获取返回的结果, 生成HTTP的Response.如下图:
web框架工作流程 code.86.01.jpg

其中, 只有URL路由和控制器部分是由用户来定义的, 所以, 如果要快速上手一个Web框架, 就要先从这两个部分入手.

1. URL路由

一般来说现在大部分的Web框架对于将HTTP请求交给哪一个逻辑来处理, 是由URL路由框架的模块来决定的. URL路由模块会提供一些函数或者装饰器等方式, 让用户来写一些代码, 将URL和控制器的绑定关系注册到框架中.

大多数的框架都支持在URL路由的定义中使用正则表达式.有的支持在URL中定义参数,框架会自动在URL中将参数截取出来保存在框架的上下文中以供控制器使用.

举几个例子:
Django的URL路由定义 code.86.02.jpg

Django是通过定义了一个数组, 其中包含了url和控制器的关系来定义的URL路由

SpringMVC定义URL路由 code.86.03.jpg

SpringMVC是通过在控制器上定义装饰器来将控制器和URL的关系注册到框架中的.

以上两种是最长用的两种注册的模式

2.控制器

控制器是用户自己实现的类或者函数, 用来处理HTTP请求, 确切的说是指定URL发来的请求, 并且将业务逻辑的结果返回给框架, 有框架去决定如何解析成HTTP的响应数据输出.

由于是由框架来调用控制器, 所以框架不同, 对控制器的定义规范是各不相同的. 有的框架要求控制器是一个类, URL将会Map到类上, 类中定义了GET, PUT, DELETE等方法, 用来对应处理HTTP的GET, PUT, DELETE等方法的请求. 有的是将URL的不同方法的请求Map到不同的函数, 或者将URL的不同方法Map到同一个函数上执行. 这些差异和实现框架的语言有关系, 比如Java, C#等语言, 函数必须以类方法的形式定义而不能成为顶级元素, 那么这些语言的框架大多会要求将控制器定义成类, 而Python, Ruby, Javascript这些函数是顶级元素的语言, 大多数的框架都是将控制器用函数来定义, 当然也有异类, 非要用类来定义的, 比如说 Python的Tornado, 有的是两种方式都支持. 这个跟框架作者的喜好关系比较大.

框架需要给控制器提供HTTP请求的完整上下文环境,那么我们在学习框架使用的时候, 首先就要在文档中整理清楚下面的这些问题:

  • 如何获取Query String参数?

QueryString是url中?后定义的由&符号分割的key=value形式的参数, 框架会在解析HTTP协议的时候将这个部分的数据转化成比如字典之类的数据结构存起来, 然后提供相应的API去访问.但是QueryString都是只读的, 有一些框架会提供一些工具帮助用户组装URL, 比如Flask提供了url_for用来组装转跳到指定控制器的URL, 方便你在页面上渲染相应的<a>标签

  • 如何获取Form表单的数据(Json body)?

POST和PUT方法是HTTP协议中主要的接收数据的语义, 传输数据需要相应的编码方式将数据编码后放在HTTP协议的Body部分. 编码方式现在主要有两种, 一种是最古老的用Form表单编制数据的方式, 另外一种是将数据用json字符串直接放到HTTP协议的body部分. 网页上的应用多数会采用Form表单, 因为这是浏览器对Form表单的默认支持, 而App的后端大多采用JSONString放在body来传数据的方式, 优点是可以传送复杂的数据结构.

Web框架会提供相应的API去按照这两种方式获取Body的内容, 但是有的框架会根据header里的mime type来判断是不是可以按照JSON去解析body的内容.

  • 如何读取和修改cookie?

cookie是浏览器(客户端)在多次请求之间共享数据的一个数据结构, 因为HTTP协议是无状态的,所以cookie在每一次请求的时候都会从浏览器放到HTTP请求中传到服务端, 在服务端生成响应的时候也会写入HTTP响应里传回浏览器. 从而实现了在两次请求之间共享了数据.

Web框架会提供对应的API去读取和修改cookie的值, cookie是key-value形式的, 访问的方式应该和字典类似.

  • 如何获取headers?

headers对应到HTTP协议中HTTP请求的头部, 是一个key-value形式的数据格式.headers是HTTP请求的一些额外的描述信息, 比如客户端类型, 字符编码方式, 认证信息等. headers的key是固定的, 你不能自己随便定义一些特殊key, 并且headers部分也是只读的.框架会提供对应API去读取headers.

  • 如何实现页面转跳?

有些时候在处理完数据后需要通知浏览器转跳到对应的看数据的URL上去, 就需要在文档里找找如何实现页面转跳. 服务端返回给客户端一个HTTP协议中的301或者302的状态, 就可以让浏览器去执行转跳的动作, 作出这样子的HTTP响应在框架中会有对应的API.

  • 如何输出Http响应?

大多数的Web框架都是用函数(方法)的返回值来作为Http响应的body的, 所以你在很多示例中可以看到 return "hello world" 这样子的写法, 框架会自动把字符串转换成Response的对象再去做编码成Http响应的操作.

当然有一些例外, 比如Python的Tornado就是用控制器继承的基类中提供的write方法, 来向输出的流中写入数据的.

针对App的API会比较方便, 输出JSON的字符串就行了. 如果是网站的话, 需要输出HTML页面,有一些框架提供了内置的模板引擎, 用于渲染输出html内容(其实不限html, xml的内容也可以由模板引擎来渲染). 有的框架自己不提供模板引擎, 你可以用你喜欢的模板引擎来渲染.

在框架的文章中找到上述问题的答案后, 我们就可以在控制器中获取请求的上下文和控制输出了.

搞定上面内容我们就可以写逻辑了, 控制器中逻辑的一般性结构如下:
控制器代码一般逻辑 code.86.04.jpg

在学习完URL路由和控制器部分后, 你就可以尝试写一些简单的东西了, 起码一些简单的demo可以跑起来了. 接下来为了让你的Demo可以跑起来, 还需要继续学习框架的一些进一步的特性

三. 开发环境

Web框架的开发环境由其实现的语言来决定, 比如用Java的很多是Eclipse, C#是visual studio, 大公司IDE产品很多都内置集成了开发运行的环境方便调试, 而很多开源产品就五花八门了, 所以比如Python, Ruby和nodejs下的web框架大多都内置了开发服务器, 启动开发服务器就等于启动了一个小web服务器, 并且大多数都提供了检测文件改变后自动重启服务的auto reload功能.

四. 配置或者约定

配置用来自定义框架的一些特性, 不同的框架配置区别是蛮大的, 有的基于配置文件, 有的是约定优先, 有的代码本身就是配置, 所以这部分仔细看文档即可, 并且可配置的项目可能很多, 在学习阶段其实可以将文档的这部分做成Cheat Sheet方便平时查阅.

如果是约定优先的框架多半会提供脚手架工具, 熟悉脚手架工具也是很重要的一点.

五. 模板引擎

前面在控制器的部分提到了模板引擎, 模板引擎主要负责用数据替换模板上的占位符生成最终结果的文本. 工作方式可以简化为下图:
code.86.05.jpg

这里详细的说一下模板引擎部分在学习的时候要注意那一些要点:

  1. 占位符如何定义

  2. 如何定义循环

  3. 如何定义判断条件

  4. 如何对占位符加过滤器

  5. 如何定义继承模板

  6. 如何定义嵌套模板

在文档中学习完上面六点基本上就能玩转一个模板引擎了, 当然你之后还是可以继续深入学习的, 但是这六点已经可以支撑你做完完整的应用了.

六. 中间件

中间件是AOP模式统一在每个请求的开始和结束部分注入代码的机制, 最常见的有两个级别的中间件, 一个是Application级别的, 也就是在应用启动和结束的时候执行注入的代码, 另一个是Request级别的, 主要是在每个请求开始和结束的时候执行, 比如统一的鉴权,数据库连接管理(打开,关闭), 统一的错误处理 都可以在这里完成.

简单的来说如下图所示:
code.86.06.jpg

七. 统一错误处理

有的框架是提供了统一错误处理机制的, 当在控制器中发生了没有捕获或者重新抛出的异常的时候, 就会执行到统一错误处理的部分. 这里可以统一完成关闭数据库连接等清理工作.一般都是由框架内置的中间件来实现的.

八. 鉴权和Session

并不是所有的框架都提供了这两个机制的, 因为通过cookie和中间件可以很轻松的实现鉴权和Session机制. 很多框架自己提供的也不怎么好用(比如Django), 所以很多人也会自己去实现这两个机制, 如果你不知道怎么实现, 我在后面会有专门的话题来详细说明.

九. 生产部署的方式

开发的Server是顶不住正式上线后的压力的, 所以要让你应用能够正式的发布, 还需要了解如何部署生产环境.

不同的框架部署的方式也是大不一样的, 所以这个要根据框架文档来实施.

在完成上述9个步骤的学习后, 你就已经可以说是初步掌握了一个Web框架了, 还有很多细节的东西可以在开发的过程中逐步的来补充. 可以说上面的内容就是一个Web框架的最小功能集合了, 如果你想自己实现一个Web框架的话也可以参考本文, 特别是写文档的时候, 现在很多Web框架的文档写得乱七八糟语焉不详, 建议参考本文的结构写一个Quick Guide, 也好让更多的人体会到你的精心设计了.

现在你可以让用户看到页面, 也可以收到用户的请求内容, 那么数据要如何保存, 如何查询, 有那些<知识点>是需要我们掌握的? 所 以

下一章的内容是<数据库以及数据访问>

to be continue...

PS: 根据本文套路写了一个番外篇, 用一个实际框架来做了个入门指南: 实战:Flask快速入门


來源

已有 2 条评论
  1. PC

    感谢,虽然还有很多不懂。但是帮助也很大

    1. 可以在文章来源查看作者的系列文章,虽然好久没更新了。

添加新评论