RESTful
RESTful架构:一种软件的架构风格,设计风格, 为客户端和服务端的交互提供一组设计原则和约束条件。如果一个架构符合REST的约束条件和原则,就称它为RESTful架构。 REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。
web服务交互
在浏览器中能看到的每个网站,都是一个web服务。在提供每个web服务的时候, 都需要前后端交互,前后端交互就一定有一些实现方案,通常叫web服务交互方案。
目前主流的三种web服务交互方案:
- REST ( Representational State Transfer)表征性状态转移【这里所说的表征性,其实指的就是资源。通常称为资源状态转移。】
- SOAP (Simple Object Access Protocol) 简单的对象访问协议
- XML-RPC (XML Remote Procedure Call)基于XML的远程过程调用
什么是URI,URL
- 资源:任何事物,只要有被引用到的必要,它就是一个资源。资源可以是一个实体,也可以是抽象概念。比如在浏览器中看到的文本,视频,图片等等都是实体资源。也可以是抽象的概念,比如两个人的关系......
- URI(统一资源标志符)是给资源进行标识的,在web中的唯一标识就是URI
- URL(统一资源定位符)是描述资源地址的。URL可以说是URI的子集,通过定位的方式实现的URI
- URI类似身份证是唯一的,URL类似家庭住址xx省/xx市/xx村/xx号街道/xx号楼/Alex
统一资源接口
- 我们可以通过URL去访问到资源,对资源会有很多不同的操作,增删改查
- 以前可能会为了这个增加新设计一个URL,这个URL就是对数据进行增加的, 还会为了更新和删除分别设计一个URL
- 现在不用了,只有一个URL,然后根据HTTP请求方式的不同,对资源进行不同的操作,这个就是是统一资源接口
- 一定要遵循HTTP请求方法的语义,也就是说POST请求就在新增数据等....
资源的表述
- 资源的表述其实就是资源的展现形式,客户端和服务端传输的都是资源的表述,而不是资源本身
- 例如文本资源可以采用html、xml、json等格式,图片可以使用PNG或JPG展现出来
- 那么客户端如何知道服务端提供哪种表述形式呢? 可以通过HTTP内容协商,客户端可以通过Accept头请求一种特定格式的表述,服务端则通过Content-Type告诉客户端资源的表述形式。
- 这些资源的表述呈现在页面上,就是资源状态。
状态转移
- 我们在看页面的时候,从当前资源的表述(也可以说状态或者表现层)会跳转到其他的资源状态
- 服务端通过超媒体告诉客户端当前状态有哪些后续状态可以进入
- 这些类似"下一页"之类的链接起的就是这种推进状态的作用——指引你如何从当前状态进入下一个可能的状态
REST风格特点
- (1)在web中,只要有被引用的必要都叫资源。
- (2)每个URI代表一个资源,独一无二的。
- (3)客户端通过HTTP的方法,对服务器端资源进行操作;
- (4)客户端和服务器之间,传递这种资源的某种表现层;
- (5)通过超链接的指引,实现"表现层状态转移"。
RESTful规范
- 路径:面向资源编程
- 每个URL代表一种资源,URL中尽量不要用动词,要用名词(可复数)。
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
- https://api.example.com/v1/employees
- method:根据method不同,进行不同的操作
GET/POST/PUT/DELETE/PATCH
GET :从服务器取出资源(一项或多项)
POST :在服务器新建一个资源
PUT :在服务器更新资源(客户端提供改变后的完整资源)
PATCH :在服务器更新资源(客户端提供改变的属性)
DELETE :从服务器删除资源
- 版本:在URL中体现版本
https://www.bootcss.com/v1/mycss
https://v1.bootcss.com/mycss
- 域名:在URL中体现是否是API
https://www.bootcss.com/api/mycss
https://api.bootcss.com/mycss
- 过滤:通过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
- 协议:尽量使用HTTPS
https://www.bootcss.com/v1/mycss
- 状态码:
- 1** 信息,服务器收到请求,需要请求者继续执行操作
- 2** 成功,操作被成功接收并处理
- 3** 重定向,需要进一步的操作以完成请求
- 4** 客户端错误,请求包含语法错误或无法完成请求
- 5** 服务器错误,服务器在处理请求的过程中发生了错误
- 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
- 返回值:针对不同操作,服务器向用户返回的结果应该符合以下规范
- GET请求 返回查到所有或单条数据
- POST请求 返回新增的数据
- PUT请求 返回更新数据
- PATCH请求 局部更新 返回更新整条数据
- DELETE请求 返回值为空
- 错误处理:
- 状态码是4xx时,应返回错误信息,error当做key。
{ error: "Invalid API key" }
- Hypermedia API: 如果遇到需要跳转的情况 携带调转接口的URL
- RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
- RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
ret = { code: 1000, data:{ id:1, name:'小强', depart_id:http://www.luffycity.com/api/v1/depart/8/ }, link: { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" } }
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。 502:网关不可用 503:服务不可用 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常 504:网关超市 505:版本不支持
为什么要做前后端分离的项目
- 满足多端适配
- 随着移动端的兴起,现在公司产品不只限于pc端的,包括Android,IOS。
- 按照以前的方式,后端其实就要有多套,pc一套,APP端两套。
- 开发成本以及开发效率会很低,如果前后端分离,后端只需要有一套就可以了
- 后端只提供接口,前端不管是pc还是APP都可以去调用数据。
- 前后端职责不清晰
- 我们的模板语言到底是前端写还是后端写
- 开发效率 前后端互相等待
- 前端配合后端,只写模板语言,能力受限
- 后端开发语言与模板语言耦合度较高,依赖开发语言,更换后端语言的成本加大。
基于Django实现
路由系统:
urlpatterns = [ url(r'^users/$', views.Users.as_view()), url(r'^users2/$', views.user2), ]
视图函数:
import json def user2(request): if request.method=='GET': dic = {'status':200,'name': 'lqz2', 'age': 18} return HttpResponse(json.dumps(dic)) elif request.method=='POST': dic = {'status': 200, 'msg': '修改成功'} return JsonResponse(dic) class Users(View): def get(self, request): dic = {'status':200,'name': 'lqz', 'age': 18} return HttpResponse(json.dumps(dic)) def post(self, request): dic = {'status': 200, 'msg': '修改成功'} return JsonResponse(dic)