一、概念介绍1、REST概念REST:(RepresentationalStateTransfer)是表示层的状态传递。设计风格和开发方法。在概念上,你需要理解以下几个名称:资源(Resource)是指在服务器上获得的任何资源,如用户记录、用户密码、图片等。资源的表示是指资源的格式,有HTML、XML、JSON、纯文本、图片等,可以用多种格式来表示你获取的资源。StateTransfer是指URL定位资源,使用HTTP动词(GET、POST、DELETE、DETC)来描述操作。操作是动词,资源是名词。统一接口是指通过统一的接口对资源进行操作。2.REST特性REST通常是基于使用HTTP、URI、XML和HTML这些现存的广泛流行的协议和标准,每个URI代表一种资源。REST通常使用JSON数据格式。REST基本架构的四种方法:GET-用于获取数据PUT-用于更新或添加数据DELETE-用于删除数据POST-用于添加数据下面将介绍一个场景。3、REST的优点是可以更高效的使用缓存,提高响应速度。通信本身的无状态特性可以让不同的服务器处理一系列请求中的不同请求,提高了服务器的可扩展性。浏览器可作为客户端,简化软件需求。与其他叠加在HTTP协议之上的机制相比,REST的软件依赖性更小,不需要额外的资源发现机制。在软件技术演进中具有较好的长期兼容性。2.实例介绍REST定义了资源的通用访问格式,下一个consumer为例,介绍RESTfulAPI的定义:GetallusersGET/api/users获取指定id的用户GET/api/users/100创建一个新用户recordPOST/api/users更新用户记录PUT/api/users/100删除用户记录DELETE/api/users/100获取用户所有消费账单GET/api/users/100/bill获取用户消费账单在指定时间GET/api/users/100/bill?from=201910&to=201911及以上RESTful风格的API几乎包含常见的业务情况。三、Nodejs实现RESTfulAPI1、初始化mock数据本案例使用mock数据进行演示,如下:{"user1":{"name":"leo","password":"123456","profession":"teacher","id":1},"user2":{"name":"pingan8787","password":"654321","profession":"图书管理员","id":2},"user3":{"name":"robin","password":"888888","profession":"clerk","id":3}}我们将实现以下RESTfulAPI:2.获取用户列表在这一步中,我们将创建RESTfulAPI/users,使用GET方式读取用户信息列表://index.jsconstexpress=require('express');constapp=express();constfs=require("fs");//定义读取用户信息列表的接口app.get('/users',(req,res)=>{fs.readFile(__dirname+"/"+"users.json",'utf8',(err,data)=>{console.log(data);res.end(data);});})constserver=app.listen(8081,function(){const{address,port}=server.address();console.log("serverrunin:http://%s:%s",address,port);})3.在添加用户这一步,我们将创建/用户在RESTfulAPI中,使用POST添加用户记录://index.js//省略前面的文件,只显示需要实现的接口//mock一条要添加的数据constuser={"user4":{"name":"pingan","password":"password4","profession":"teacher","id":4}}//定义添加用户记录的接口app.post('/users',(req,res)=>{//读取现有数据fs.readFile(__dirname+"/"+"users.json",'utf8',(err,data)=>{data=JSON.parse(data);data["user4"]=user["user4"];console.log(data);res.end(JSON.stringify(data));});})4.在获取用户详情这一步,我们在RESTfulAPI中的URI:id后面添加/users/,使用GET获取指定用户的详情://index.js//省略前面的文件,只显示界面需要实现的//定义获取指定用户详情的接口app.get('/users/:id',(req,res)=>{//首先我们读取已有用户fs.readFile(__dirname+"/"+"users.json",'utf8',(err,data)=>{data=JSON.parse(data);constuser=data["user"+req.params.id]控制台。日志(用户);res.end(JSON.stringify(用户));});})5。这一步我们将删除指定用户在RESTfulAPI中创建/users,使用DELETE删除指定用户://index.js//只省略前面的文件显示需要实现的接口//mock一个要删除的用户idconstid=2;app.delete('/users',(req,res)=>{fs.readFile(__dirname+"/"+"users.json",'utf8',(err,data)=>{data=JSON.parse(data);deletedata["user"+id];console.log(data);res.end(JSON.stringify(data));});})4.REST最佳实践1.URL设计1.1“Verb+Object”操作指令结构客户端下发的数据操作指令都是“verb+object”结构如前所述,GET/对于用户命令,GET是动词,/user是宾语。根据HTTP规范,动词始终大写。Verbs通常有以下五个HTTP方法:GET:读取(Read)POST:新建(Create)PUT:更新(Update)PATCH:更新(Update),通常是部分更新DELETE:删除(Delete)1.2对象必须是一个名词对象是API的URL,HTTP动词作用于其上。应该是名词,不是动词。比如/users是正确的,因为url是名词,下面都是错误的:/getUsers/createUsers/deleteUsers1.3建议用复数url,因为url是名词,没有单复数限制,但还是推荐如果是集合,则使用复数形式。例如GET/users读取所有用户的列表。1.4避免多级URL使用多级资源时避免使用多级URL。常见的情况,比如获取某个用户购买的某类商品:GET/users/100/product/120这种URL语义不明确,不利于扩展。建议只有第一层,其他层用querystring表示:GET/users/100?product=1202。准确的状态码是指HTTP状态码有5大类100多种,每种状态码都有标准(或约定)的解释。可以判断发生了什么,因此服务器应该尽可能返回最准确的状态代码。下面介绍几个常用的状态码:303SeeOther:指的是另一个URL。400BadRequest:服务器不理解客户端的请求,没有处理。401Unauthorized:用户未提供身份验证凭据,或未通过身份验证。403Forbidden:用户已通过身份验证,但没有访问资源所需的权限。404NotFound:请求的资源不存在,或者不可用。405MethodNotAllowed:用户已经通过认证,但是使用的HTTP方法不在他的权限范围内。410Gone:请求的资源已从该地址转移,不再可用。415UnsupportedMediaType:不支持客户端请求的返回格式。比如API只能返回JSON格式,而客户端请求返回XML格式。422UnprocessableEntity:客户端上传的附件无法处理,导致请求失败。429TooManyRequests:客户端请求数量超过限制。500InternalServerError:客户端请求有效,但服务器处理时出现异常。503ServiceUnavailable:服务器无法处理请求,一般用于网站维护状态。3、服务器响应3.1应返回JSON对象API返回的数据格式应为JSON对象。3.2发生错误时,不返回200状态码。发生错误时,如果返回200状态码,前端需要解析返回的数据才能知道错误信息。这实际上取消了状态码,这是不合适的。正确的做法应该是返回相应的错误状态码,出错时返回错误信息:HTTP/1.1400BadRequestContent-Type:application/json{"error":"Invalidpayoad.","detail":{"surname":"此字段为必填项。"}}参考《维基百科 - 表现层状态转换》《RESTful风格的springMVC》《Node.js RESTful API》《RESTful API 最佳实践》关于我
