`

7点关于RESTful规范的API接口设计的想法

 
阅读更多

转:https://segmentfault.com/a/1190000004051246

 

在项目中,需要为APP撰写API。刚开始接触的时候,并没有考虑太多,就想提供URL,APP端通过该URL进行查询、创建、更新等操作即可。但 再对相关规范进行了解后,才发现,API的设计并没有那么简单,远远不是URL的问题,而是一个通信协议的整体架构。因此,我写这篇文章,用来记录自己的 一些心得,并不断完善。并提供关于RESTful API的一些参考文献。

1. 使用SSL(https)来提供URL

首先,使用https可以在数据包被抓取时多一层加密。我们现在的APP使用环境大部分都是在路由器WIFI环境下,一旦路由器被入侵,那么黑客可 以非常容易的抓取到用户通过路由器传输的数据,如果使用http未经加密,那么黑客可以很轻松的获取用户的信息,甚至是账户信息。

其次,即使使用https,也要在API数据传输设计时,正确的采用加密。例如直接将token信息放在URL中的做法,即使你使用了https,黑客抓不到你具体传输的数据,但是可以抓到你请求的URL啊!(查了资料了,https用GET方式请求,也仅能抓到域名字符部分,不能抓到请求的数据,但是URL可以在浏览器或特殊客户端工具中直接看到。多谢下面的朋友指正错误)因此,使用https进行请求时,要采用POST、PUT或者HEAD的方式传输必要的数据。

2. 使用GET、POST、PUT、DELETE这几种请求模式

请求模式也可以说是动作、数据传输方式,通常我们在web中的form有GET、POST两种,而在HTTP中,存在下发这几种。

GET (选择):从服务器上获取一个具体的资源或者一个资源列表。
POST (创建): 在服务器上创建一个新的资源。
PUT(更新):以整体的方式更新服务器上的一个资源。
PATCH (更新):只更新服务器上一个资源的一个属性。
DELETE(删除):删除服务器上的一个资源。
HEAD : 获取一个资源的元数据,如数据的哈希值或最后的更新时间。
OPTIONS:获取客户端能对资源做什么操作的信息。

3. 在URI中体现资源,而非动作

阅读RESTful架构的参考文献之后,你会了解什么是资源的概念,以及REST的确切含义。再构建API的URL的时候,URI中应该仅包含资源 (对象),而不要加入动作。比如 /user/1/update ,其中update就是一个动作,虽然我们希望通过这个URI来实现用户ID为1的用户进行信息更新,但是按照RESTful的规范,作为动作,应该用上 面的PUT来表示,所以请求更新用户信息,应该使用 PUT /user/1 来表示更新用户ID为1的用户信息。

如果去对应上面的请求模式,GET表示显示、列出、展示,POST表示提交、创建,PUT表示更新,DELETE表示删除。

<?php
    $ch = curl_init();
    $url = 'http://api.xxx.com/user';
    $data = "name=姓名&email=xxx@xxx.com";
    // 添加参数
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // 执行HTTP请求
    curl_setopt($ch , CURLOPT_URL , $url);
    $res = curl_exec($ch);

    var_dump(json_decode($res));
?>

上面这段代码中$url仅仅是提供到了user,而并没有提供add,服务端通过识别POST请求来确定,这是一个创建用户的操作。但是还有一些数据并没有用以处理数据,而是用以验证的,比如下文的鉴权,可以将这些信息通过header进行传输,下方详细展示。

4. 版本

API的开发直接关系了APP是否可以正常使用,如果原本运行正常的API,突然改动,那么之前使用这个API的APP可能无法正常运行。APP是 不可能强迫用户主动升级的,因此,通过API版本来解决这个问题。也就是说,API的多个版本是同时运行的,而且都要保证可以正常使用。

按照RESTful的规范,不同的版本也应该用相同的API URL,通过header信息来判断版本,再调用不同版本的程序进行处理。但是这明显会给开发带来巨大的成本。解决办法有两种:1.新版本兼容旧版本,所 有旧版本的动作、字段、操作,都在新版本中可以被实现,但明显这样的维护成本很大;2.不同的版本,用不同的URL来提供服务,比如再URL中通过v1、 v2来区分版本号,我则更喜欢采用子域名的方式,比如v2.api.xxx.com/user的方式。

5. HTTP响应码

在用户发出请求,服务端对请求进行响应时,给予正确的HTTP响应状态码,有利于让客户端正确区分遇到的情况。

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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

6. 返回值结构

在完成了上面的URL部署之后,接下来我们来看看返回结果应该怎么样来确定。我看到大部分文献中指出,最好使用JSON进行返回,而非xml。我认 为原因可能有两点:1. JSON可以很好的被很多程序支持,javascript的ajax可以直接将JSON转换为对象。2. JSON的格式在容量上比xml小很多,可以减低宽带占用,提高传输效率。

那么,返回值应该怎么去部署呢?

首先,字段的合理返回,数据的包裹。因为返回值中,我们常常要对数据进行区分分组,或者按照从属关系打包,所以,我们再返回时,最好有包裹的思想,把数据存放在不同的包裹中进行返回。

{
  'error_code' : 0,
  'data' : {
                   'user_id' : 1,
                   'username' : 'xiaomin'
              },
  'server_time': 14939939
}

上面返回的JSON中,使用data来作为数据包,将所有数据统一以这个字段进行包裹。除了data,也可以用list等其他形式的包裹,命名都是自己来根据自己的需要确定的。

{
  'error_code' : 0,
  'list' : [
              {'user_id':1,'username':'xiaoming'},
              {'user_id':2,'username':'goudan'}
            ]
  'server_time': 14939939
}

总之,不要不分包,直接把所有数据和一些你想返回的全局数据混在一起进行返回。

其次,错误码。错误码的作用是方便查找错误原因,通常情况下,我喜欢用error_code来表示,当error_code=0时,表示没有发生错 误,当error_code>0时,发生了错误,并且提供较为详细的文档,告诉客户端对应的error_code值所产生的错误的原因和位置。

最后,空白压缩和字符转换。也就是返回的JSON结果不要换行和空格,用一行返回结果,使整个结果文本容量最小。同时,中文等字符或结果中有引号,都进行字符转换,防止结果无法被正确识别。

7. 鉴权

其实也就是客户端的权限控制。一般而言,我会采用给客户端分发一个token来确定该客户端的唯一身份。客户端在请求时,通过这个token,判断发出请求的客户端所对应的用户,及其相关信息和权限。

前文已经提到了,token信息不是用来进行处理的数据,虽然可以通过POST、PUT等进行数据提交或传输,但是从RESTful规范来讲,它不属于操作数据,在服务端进行处理时,仅是利用token进行鉴权处理,所以,我的建议是通过header来发送token。

<?php
    $ch = curl_init();
    $url = 'http://api.xx.com/user';
    $header = array(
        'token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        'X-HTTP-Method-Override: PUT'        
    );
    $data = array(
         'user_name' => 'xiaoming',
         'user_email' => 'xx@sfa.com'
    );
    // 添加apikey到header
    curl_setopt($ch, CURLOPT_HTTPHEADER  , $header);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // 执行HTTP请求
    curl_setopt($ch , CURLOPT_URL , $url);
    $res = curl_exec($ch);

    var_dump(json_decode($res));
?>

上面的代码中,通过将CURLOPT_CUSTOMREQUEST设置为PUT,就可以发出PUT请求,发出的PUT请求,仍然需要通过 CURLOPT_POSTFIELDS来传输数据。服务端接受PUT请求时,首先要对发出请求的客户端进行token验证,通过对token的处理,查找 到拥有该token的实际用户,从而确定了将对哪一个用户进行信息更新操作。

国内大部分API对PUT、DELETE请求进行了阉割,更不用提HEAD、PACTH、OPTIONS请求。实际上,国内大部分开放API仅支持 GET和POST两种,部分API支持将app key信息通过header进行发送。在面对这种情况下,我们不得不抛弃标准的RESTful规范,在url中加入get、add、update、 delete等动作词汇,以补充由于请求支持不完善带来的动作区分问题。如果仅支持GET和POST,那么所有需要保密的数据,绝对不可以用GET来进行 请求,而必须用POST。

参考文献

《理解RESTful架构》《RESTful API 设计指南》
《好RESTful API的设计原则》
《我所理解的RESTful Web API [设计篇]》
《https工作原理》

 

 

分享到:
评论

相关推荐

    api:关于有效API设计的想法

    - Go语言强调简洁和强类型,因此Go API设计应充分利用接口和结构体,提供类型安全的调用。 - 使用Go的错误处理机制,返回错误值而不是抛出异常。 - 利用Go的上下文(Context)包来处理请求取消和超时。 3. 文档...

    基于微信小程序的在线投稿系统

    5. **API接口设计**:为了实现微信小程序与后台服务器的通信,需要设计一系列API接口,如用户注册/登录接口、投稿接口、获取投稿列表接口、评论接口等,这些接口需要遵循RESTful原则,以JSON格式传输数据。...

    基于ssm的二次元周边产品分期平台源码数据库.zip

    总的来说,这个项目是一个综合性的Web和移动应用平台,涵盖了前后端开发、数据库设计、API接口等多个方面,展示了开发者对Java Web技术栈的熟练掌握,以及对二次元文化和消费市场的理解。通过此项目,学习者可以深入...

    web博客开发

    7. **API接口**:为了与其他服务集成,博客可能需要提供API,如允许用户通过第三方应用登录(OAuth)或发布到社交媒体。RESTful API是一种常见的设计风格,它遵循HTTP协议规范来交换数据。 8. **用户认证与授权**:...

    springboot基于微信小程序的校园心声墙小程序论文和ppt.zip

    在开发过程中,Spring Boot后端可能采用了RESTful API设计原则,提供JSON格式的接口供微信小程序调用。微信小程序则通过这些接口获取数据,显示在界面上,并发送用户的操作回传到服务器。此外,项目可能还涉及了微信...

    diary:写下您的想法,表达您的感受,并记录您的身份

    5. API设计:定义API接口,如创建日记、查看日记、编辑日记等,确保符合RESTful规范。 6. 实现业务逻辑:在控制器层处理API请求,调用DAL进行数据操作。 7. 用户认证:集成身份验证机制,如JWT(JSON Web Tokens),...

    留言板留言板

    5. **RESTful API**:用于前端和后端之间的通信,遵循统一的接口规范。 6. **安全措施**:使用HTTPS协议保护用户数据传输,XSS和CSRF防护来防止跨站脚本和请求伪造攻击。 7. **部署与服务器**:可能使用Apache、...

    高级前端工程师简历模板

    6. **API接口交互**: 与后端服务进行数据交互,理解RESTful API设计原则,熟悉JSON格式,能处理异步请求和错误处理。 7. **测试与调试**: 熟悉Jest、Mocha等测试框架,能够编写单元测试和集成测试。掌握Chrome ...

    WeShare-Blog:一个博客网站

    7. **RESTful API**:与后端服务器进行数据交互,遵循一套标准的HTTP接口设计规范。 8. **Node.js/Express**: 如果项目采用前后端分离,可能使用Node.js和Express框架构建后端服务,处理请求、验证和数据库操作。 9....

    uni-app+unicloud仿奈雪の茶点餐

    在前后端联调过程中,开发者需要掌握RESTful API的设计原则,确保接口的清晰和规范。unicloud的云数据库服务可以提供实时的CRUD操作,配合uni-app的axios库或uni.request方法,实现前后端数据的同步。同时,unicloud...

    microproject

    - **API设计**:微型项目可能涉及API交互,遵循RESTful原则设计接口。 - **数据库管理**:SQLite、MySQL等轻量级数据库用于存储数据,对于微型项目足够高效。 4. **实施过程** - **需求分析**:明确项目目标,列...

    匿名聊天微信小程序

    它能与微信小程序前端进行有效交互,通过RESTful API接口发送和接收数据,确保用户可以安全地登录、创建聊天室、发送和接收匿名消息。 WebSocket是一种在客户端和服务器之间建立长连接的协议,允许双向通信。在微信...

    企业数字化转型与数据治理整体规划方案59页.pptx

    - 通过API接口实现数据实时交换,提升业务协同效率。 - **数据治理组织与流程优化:** - 成立专门的数据治理团队,负责制定数据标准、规范操作流程等工作。 - 定期开展数据治理培训,提高员工数据意识和技能水平...

    akka-http-scalajs.g8:Giter8模板开始使用Akka HTTP和Scala.js

    **正文** ... 首先,让我们了解基础概念: ...Akka HTTP以其异步、非阻塞I/O和高效的路由设计而著称,是构建微服务和API的理想选择...通过熟悉这个模板和其背后的原理,你将能够更快地将想法转化为实际的、可部署的软件。

    mebo:专注于跨多个域提供统一接口的框架

    mebo的想法是提供一个平台,在此平台上可以简单地定义及其。 完成的方式使您能够以一种相当有表现力的方式来建立带有验证的严格规范。 Mebo中的评估是通过推广不需要过于耦合到特定域的实现而暴露出来的,避免了将...

Global site tag (gtag.js) - Google Analytics