【全栈修炼】RESTful架构及实践 修炼宝典

简介: 【全栈修炼】RESTful架构及实践 修炼宝典


一、概念介绍

1. REST 概念

REST:(Representational State Transfer)即表现层状态转换,定义了资源的通用访问格式,是一种网络应用程序的设计风格开发方式

在概念中,需要理解以下几个名称:

  1. 资源(Resource)

服务器上获取到的东西任何资源,一条用户记录,一个用户的密码,一张图片等等都是。

  1. 资源的表述(Representation)

资源格式,是 HTML、XML、JSON、纯文本、图片等等,可以用各种各样的格式来表述你获取到的资源。

  1. 状态转移(State Transfer)

URL定位资源,用 HTTP 动词(GET,POST,DELETE,DETC)描述操作。操作是动词,资源是名词。

  1. 统一接口(Uniform Interface)

即通过统一的接口对资源进行操作。

2. REST 特点

REST 通常基于使用 HTTPURI ,和 XML 以及 HTML 这些现有的广泛流行的协议和标准,每一种 URI 代表一种资源。

REST 通常使用 JSON 数据格式。

REST 基本架构的四个方法:

  • GET - 用于获取数据
  • PUT - 用于更新或添加数据
  • DELETE - 用于删除数据
  • POST - 用于添加数据

下面会通过一个场景介绍。

3. REST 优点

  • 可更高效利用缓存来提高响应速度
  • 通讯本身的无状态性可以让不同的服务器的处理一系列请求中的不同请求,提高服务器的扩展性
  • 浏览器即可作为客户端,简化软件需求
  • 相对于其他叠加在HTTP协议之上的机制,REST的软件依赖性更小
  • 不需要额外的资源发现机制
  • 在软件技术演进中的长期的兼容性更好

二、实例介绍

REST 定义了资源的通用访问格式,接下来一个消费者为实例,介绍 RESTful API 定义:

  1. 获取所有 users
GET /api/users
  1. 获取指定 id 的 users
GET /api/users/100
  1. 新建一条 users 记录
POST /api/users
  1. 更新一条 users 记录
PUT /api/users/100
  1. 删除一条 users 记录
DELETE /api/users/100
  1. 获取一个 users 的所有消费账单
GET  /api/users/100/bill
  1. 获取一个 user 指定时间的消费账单
GET  /api/users/100/bill?from=201910&to=201911

以上其中 RESTful 风格 API 几乎包含常见业务情况。

三、Nodejs 实现 RESTful API

1. 初始化 mock 数据

本案例使用 mock 数据来演示,如下:

{
   "user1" : {
      "name" : "leo",
      "password" : "123456",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "pingan8787",
      "password" : "654321",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "robin",
      "password" : "888888",
      "profession" : "clerk",
      "id": 3
   }
}

我们将实现以下 RESTful API :

2. 获取用户列表

这一步我们会创建 RESTful API 中的 /users,使用 GET 来读取用户的信息列表

// index.js
const express = require('express');
const app = express();
const fs = require("fs");
// 定义 读取用户的信息列表 的接口
app.get('/users', (req, res) => {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       console.log( data );
       res.end( data );
   });
})
const server = app.listen(8081, function () {
    const {address, port} = server.address();
    console.log("server run in: http://%s:%s", address, port);
})

3. 添加用户

这一步我们会创建 RESTful API 中的 /users,使用 POST 来添加用户记录

// index.js
// 省略之前文件 只展示需要实现的接口
// mock 一条要新增的数据
const user = {
   "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. 获取用户详情

这一步我们在 RESTful API 中的 URI 后面加上 /users/:id,使用 GET 来获取指定用户详情

// index.js
// 省略之前文件 只展示需要实现的接口
// 定义 获取指定用户详情 的接口
app.get('/users/:id', (req, res) => {
   // 首先我们读取已存在的用户
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       const user = data["user" + req.params.id] 
       console.log( user );
       res.end( JSON.stringify(user));
   });
})

5. 删除指定用户

这一步我们会创建 RESTful API 中的 /users,使用 DELETE 来删除指定用户

// index.js
// 省略之前文件 只展示需要实现的接口
// mock 一条要删除的用户id
const id = 2;
app.delete('/users', (req, res) => {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', (err, data) => {
       data = JSON.parse( data );
       delete data["user" + id];
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

四、REST 最佳实践

1. URL 设计

1.1 "动词 + 宾语"的操作指令结构

客户端发出的数据操作指令都是"动词 + 宾语"的结构。

如上面提到的,GET /user 这个命令,GET 是动词,/user 是宾语。根据 HTTP 规范,动词一律大写。

动词通常有以下五种 HTTP 方法:

GET:读取(Read) POST:新建(Create) PUT:更新(Update) PATCH:更新(Update),通常是部分更新 DELETE:删除(Delete)

1.2 宾语必须是名词

宾语就是 API 的 URL,是 HTTP 动词作用的对象。它应该是名词,不能是动词。

比如,/users 是正确的,因为 URL 是名词,而下面就都是错误的了:

/getUsers
/createUsers
/deleteUsers

1.3 建议复数 URL

因为 URL 是名词,没有单复数的限制,但是还是建议如果是一个集合,就使用复数形式。如 GET /users 来读取所有用户列表。

1.4 避免多级 URL

避免在多层级资源时,使用多级 URL。常见案例如获取某位用户的购买过的某一类商品:

GET /users/100/product/120

这种 URL 语意不明,也不利拓展,建议只有第一级,其他级别用查询字符串来表达:

GET /users/100?product=120

2. 准确的状态码表示

HTTP 五大类状态码有100多种,每一种状态码都有标准的(或者约定的)解释,客户端只需查看状态码,就可以判断出发生了什么情况,所以服务器应该返回尽可能精确的状态码。

这边列举几个经常使用的状态码介绍:

  • 303 See Other:表示参考另一个 URL。
  • 400 Bad Request:服务器不理解客户端的请求,未做任何处理。
  • 401 Unauthorized:用户未提供身份验证凭据,或者没有通过身份验证。
  • 403 Forbidden:用户通过了身份验证,但是不具有访问资源所需的权限。
  • 404 Not Found:所请求的资源不存在,或不可用。
  • 405 Method Not Allowed:用户已经通过身份验证,但是所用的 HTTP 方法不在他的权限之内。
  • 410 Gone:所请求的资源已从这个地址转移,不再可用。
  • 415 Unsupported Media Type:客户端要求的返回格式不支持。比如,API 只能返回 JSON 格式,但是客户端要求返回 XML 格式。
  • 422 Unprocessable Entity:客户端上传的附件无法处理,导致请求失败。
  • 429 Too Many Requests:客户端的请求次数超过限额。
  • 500 Internal Server Error:客户端请求有效,服务器处理时发生了意外。
  • 503 Service Unavailable:服务器无法处理请求,一般用于网站维护状态。

3. 服务端响应

3.1 应该返回 JSON 对象

API 返回的数据格式应该是 JSON 一个对象。

3.2 发生错误时,不要返回 200 状态码

在发生错误时,如果还返回 200 状态码,前端需要解析返回数据才知道错误信息,这样实际上取消了状态码,是不恰当的。

正确的做法应该是在错误时,返回对应错误状态码,并将错误信息返回:

HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "Invalid payoad.",
  "detail": {
     "surname": "This field is required."
  }
}

参考资料

  1. 《维基百科 - 表现层状态转换》
  2. 《RESTful风格的springMVC》
  3. 《Node.js RESTful API》
  4. 《RESTful API 最佳实践》


目录
相关文章
|
14天前
|
监控 Java 持续交付
后端开发中的微服务架构实践与挑战####
在当今快速迭代的软件开发领域,微服务架构以其灵活性和可扩展性成为众多企业的首选。本文探讨了微服务架构的核心概念、实施策略及面临的主要挑战,旨在为后端开发者提供一个全面的指南。通过分析真实案例,揭示微服务在提升系统敏捷性的同时,如何有效应对分布式系统的复杂性问题。 ####
|
4天前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
23 1
|
5天前
|
消息中间件 运维 开发者
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在后端开发中的应用,从其核心概念、设计原则到实际部署过程中面临的挑战进行了全面剖析。不同于传统的单体应用,微服务通过将复杂系统拆解为一系列小型、独立的服务,提高了系统的灵活性和可维护性。然而,这种架构的转变也伴随着服务间通信、数据一致性、部署复杂性等新问题。本文旨在为开发者提供一套应对这些挑战的策略,同时分享一些成功案例,以期促进微服务架构的有效实施。 ####
|
7天前
|
缓存 负载均衡 API
后端开发中的微服务架构实践与挑战####
在数字化转型的浪潮中,微服务架构凭借其高度的可扩展性、灵活性及易于维护的特点,成为众多企业后端开发的首选架构模式。本文将深入探讨微服务架构的核心理念,通过具体案例分析其在实际应用中的实践策略与面临的挑战,为读者提供一份详尽的微服务架构实施指南。 ####
|
9天前
|
消息中间件 负载均衡 测试技术
后端开发中的微服务架构实践与挑战####
本文旨在探讨微服务架构在后端开发中的应用实践,深入分析其带来的优势与面临的挑战。通过剖析真实案例,揭示微服务转型过程中的关键技术决策、服务拆分策略、以及如何有效应对分布式系统的复杂性问题。文章还将提供一套评估企业是否适合采用微服务架构的框架,帮助读者更好地理解这一架构模式,并为企业的技术选型提供参考。 ####
|
8天前
|
运维 监控 安全
深入理解微服务架构:设计原则、挑战与实践
深入理解微服务架构:设计原则、挑战与实践
|
13天前
|
Cloud Native Devops 持续交付
云原生架构的演进与实践
本文深入探讨了云原生架构的核心概念、技术组件及其在现代软件开发中的应用。通过分析容器化、微服务、持续集成/持续部署(CI/CD)等关键技术,揭示了这些技术如何共同促进应用程序的灵活性、可扩展性和高可用性。文章还讨论了云原生架构实施过程中面临的挑战和最佳实践,旨在为开发者和企业提供一套实用的指导方针,以便更有效地利用云计算资源,加速数字化转型的步伐。
30 5
|
15天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
42 5
|
18天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
16天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####