记Angular与Django REST框架的一次合作(1):分离 or 不分离,it's the question

前言:本次尝试源于我们内部的一个项目,由于前端逻辑比较复杂,就打算将前后端分开来开发。由于之前用Django开发过软件,对AngularJS(Angular 1.0版)也有一定的了解,因此就将技术路线锁定在了这两个开源工具上,用Angular做前端(这次是Angular 2),Django做后端。

这个系列计划分为以下四个部分:

(1): 分离 or 不分离,it's the question

(2):前端组件化——Angular

(3):后端服务化——Django REST框架

(4):前后端的通信——跨域请求

 

 

前后端的关系


前后端是否分离是我们设计网站应用程序架构时需要想清楚的首要问题。这直接影响了我们的开发流程,技术路线,甚至后期的维护。

要搞清楚是否需要分离,首先要明白前后端各自最主要的职责是什么。

 

关于前端

  • 之所以叫做前端,是因为相对于服务器端,这部分是直接与用户接触的;
  • 前端三件宝:html, css, JavaScript;
  • 主要职责:负责网站内容的展示,接受用户的输入并作出相应的反馈(包括用户输入有效性的验证,将输入的数据传给服务器,接受服务器传回的数据并作出正确反应);

 

关于后端

  • 对前端的请求作出响应;
  • 数据的验证(再次验证);
  • 数据的预处理和分析(可以调用系统资源);
  • 数据的持久化(保存到数据库或文件系统);
  • 当然还有很多其他的功能,例如保存负载均衡等,但是最重要的一个工作是为前端提供数据;
  • 后端的开发语言比前端的选择空间大得多,例如Java、Ruby,PHP等,当然还有Python.

 

总的来说,前端可以看做是数据的消费者(当然也可以是数据的来源),后端则可以看成是数据的生产者(来源于数据库或对输入数据的加工)。那么如何判断前后端是否分离了呢,这个问题的核心在什么地方呢?
其实就在于模板的与数据结合的位置,以及,模板的控制权在谁手里。
 
 

不分离的情况


之前用Django开发软件时,并没有深刻的感受到Django在网站开发上作为一个框架的完美主义(大包大揽)。最近回顾之前做的一些工作时,才发现了这一事实。利用Django,不用分离出前端,也可以做出非常棒的网站。因为Django中自带开发一个网站的全部要素——基本配置、路由、视图、模型,表单,模板,模板的渲染等。

如果前后端放在一起,使用Django的模板系统(模板的控制权在后端),这样做最大的好处就是数据可以从前端的表单(Form)直接提交给后端的视图函数(View function);数据在视图函数中经过处理后可以直接传递给模板(template),最终将渲染后的模板展示给用户。在这个过程中,数据流如下:

html -> Python -> (JavaScript) -> html
  • html -> Python:通常情况下,是从html接受表单的输入,然后使用PUT或POST方法直接提交给Django的视图函数;
  • Python -> JavaScript:数据经过视图函数的处理,最后可以转换成JSON格式传递给JS;
  • JavaScript -> html:由JS进一步处理后的数据可以通过对html中DOM的操作反映到前端,也可以使用一些前端框架(例如AngularJS的双向绑定)将数据传给html;
  • Python -> html:数据也可以经过视图函数处理后,直接传给模板(JSON格式或由字典构成的数组),在模板中可以使用{{ data }}这种格式直接消费视图函数传递的数据。

在整个过程中,数据的交换都是同源的,这样操作方便,安全性也高。同源就是指http请求之间的协议、域名和端口都相同。

此时模板的控制权和数据与模板的结合位置都在后端。

 

当需要分离时。。。


前后端统一有很多好处,开发起来也省时省力。那么在什么情况下需要分离呢?

  • 前端逻辑比较复杂;
  • 对UI的要求比较高(并不是说Django的模板丑,而是自己的css技术不够);
  • 提高代码的可维护性和可扩展性;

分离之后,Django就不用处理模板的渲染,路由这些事务了。后端专注于提供数据,更重要的职责是维护系统架构的稳定,保证数据的安全。前端人员专注于交互,快速响应UI的变化。

 

程序的结构

分离前程序其实就是一个单一的Django程序,一切基本上都可以用Django搞定。但是分离之后,Django就只负责后端的数据,前端就完全不由它管了。如果前端使用Angular,那么此时就相当于有两个程序:前端的Angular程序,后端的Django程序。那么问题就来了,这两个程序之间怎么交换数据呢?这时候有一个方法就是将后端设计成REST(Representational State Transfer,又称具象状态传输)结构。

此外还有一个问题需要解决,分离前数据是在同一个程序内部传递的,属于同源传递,这是浏览器默认就支持的行为;但是分离后,数据需要在两个不同的程序之间传递,这两个程序必定是不同源的,至少是端口不同,为了安全方面的考虑,这样的操作是被限制的。这时就需要解决跨源资源请求的问题,现在用的比较多的是CORS(Cross-Origin Resource Sharing,跨源资源分享)。

 

图1:前后端分离后,它们通过http协议进行通信

如图1所示,前后端分离后,客户端通过http协议,使用GET、POST、PUT、DELETE等动词对资源发出请求(Request);服务器端收到请求后,完成相应的操作或通过http协议返回客户端需要的资源(Response)。

 

具象状态传输,REST


REST(Representational State Transfer,又称具象状态传输)是Roy Thomas Fielding博士于2000年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。目前在三种主流的Web服务实现方案中,因为REST模式与复杂的SOAP和XML-RPC相比更加简洁,越来越多的web服务开始采用REST风格设计和实现。

需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML以及HTML这些现有的广泛流行的协议和标准。

 

要理解什么是REST,我们需要理解下面几个概念:

  • 资源(Resources):REST是"表现层状态转化",其实它省略了主语。"表现层"其实指的是"资源"的"表现层"。那么什么是资源呢?就是我们平常上网访问的一张图片、一个文档、一个视频等。这些资源我们通过URI来定位,也就是一个URI(Uniform Resource Identifier,统一资源标志符)表示一个资源。
  • 表现层(Representation):资源是一个具体的实体信息,可以有多种的展现方式。而把实体展现出来就是表现层,例如一个txt文本信息,他可以输出成html、json、xml等格式,一个图片也可以jpg、png等方式展现,这个就是表现层的意思。URI确定一个资源,但是如何确定它的具体表现形式呢?应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。
  • 状态转化(State Transfer):访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,肯定涉及到数据和状态的变化。而HTTP协议是无状态的,那么这些状态肯定保存在服务器端,所以如果客户端想要通知服务器端改变数据和状态的变化,肯定要通过某种方式来通知它。客户端能通知服务器端的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源,如图2所示。

综合上面的解释,总结一下什么是RESTful架构:

(1)每一个URI代表一种资源;
(2)客户端和服务器之间,传递这种资源的某种表现层;
(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"(对于浏览器前的用户来说就是,对界面的操作得到了恰当的反馈)。

 

图2:客户端通过http协议中的几个动词对资源进行操作

 

REST架构风格最重要的架构约束有6个:

  • 客户-服务器(Client-Server):通信只能由客户端单方面发起,表现为请求-响应的形式。

  • 无状态(Stateless):通信的会话状态(Session State)应该全部由客户端负责维护。

  • 缓存(Cache):响应内容可以在通信链的某处被缓存,以改善网络效率。

  • 统一接口(Uniform Interface):通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。

  • 分层系统(Layered System):通过限制组件的行为(即每个组件只能“看到”与其交互的紧邻层),将架构分解为若干等级的层。

  • 按需代码(Code-On-Demand,可选):支持通过下载并执行一些代码(例如Java Applet、Flash或JavaScript),对客户端的功能进行扩展。

 

 

跨域资源共享,CORS


CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

 

实现条件

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

 

在Django中的实现

在Django中,需要安装一个包来支持CORS操作,django-cors-headers可以帮我们添加需要的头信息,从而让Django支持跨域资源共享。具体可以参考django-cors-headers的官方文档。本文也会在后面详细介绍。

 

接下来会介绍Angular... 敬请期待。

 

Reference


https://zh.wikipedia.org/wiki/REST

https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/08.3.md

 http://www.ruanyifeng.com/blog/2016/04/cors.html

 https://github.com/ottoyiu/django-cors-headers

 

posted @ 2017-08-04 17:21  昕-2008  阅读(3514)  评论(0编辑  收藏  举报