前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >最流行六种的 API 架构风格(附 Node.js DEMO)

最流行六种的 API 架构风格(附 Node.js DEMO)

作者头像
Cellinlab
发布2023-06-01 10:43:14
1.7K0
发布2023-06-01 10:43:14
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog

本篇将介绍六种最流行的 API 架构风格,分别是 SOAP、RESTful、GraphQL、gRPC、WebSocket 和 Webhook。对于每种 API 架构风格,我们将深入探讨其优点、缺点以及适用场景,并提供相应的 DEMO 以帮助读者更好地理解每种 API 架构的实现方法和运作原理。

# 前言

API 在现代软件开发中扮演着重要的角色,它们是不同应用程序之间的桥梁,使得这些应用程序可以相互交互。

以下是六种最流行的 API 架构风格:

# SOAP

SOAP(Simple Object Access Protocol) (opens new window) 是一种轻量级协议,用于在去中心化、分布式环境中交换信息。

它是一种基于 XML 的协议,一条 SOAP 消息就是一个普通的 XML 文档,包含下面元素:

  • Envelope:定义消息的开始和结束
  • Header:包含头部信息
  • Body:包含消息主体
  • Fault:包含错误信息

SOAP 可以与多种其他协议结合使用。

# DEMO

server.js

代码语言:javascript
复制
const soap = require("soap");
const express = require("express");

const fs = require("fs");

const port = 8000;
const xml = fs.readFileSync("service.wsdl", "utf8");

const app = express();

app.get("/", (req, res) => {
  res.send("Hello SOAP!");
});

const service = {
  MyService: {
    MyServicePort: {
      sayHello(args) {
        return {
          msg: `Hello ${args.name}!`,
        };
      },
    },
  },
};

app.listen(port, () => {
  const soapServer = soap.listen(app, "/wsdl", service, xml);

  console.log(`SOAP service listening at http://localhost:${port}/wsdl?wsdl`);

  soapServer.log = (type, data) => {
    console.log(type, data);
  };
});

service.wsdl

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!-- <definitions> must be the root of the WSDL document -->
<wsdl:definitions targetNamespace="http://tempuri.org/"
  xmlns:s="http://www.w3.org/2001/XMLSchema"
  xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
  xmlns:tns="http://tempuri.org/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <!-- WSDL TYPES: definition of the data types that are used in the web service -->
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
      <s:element name="SayHelloRequest">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="name" type="s:string"/>
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="SayHelloResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="unbounded" name="msg" type="s:string"/>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </wsdl:types>
  <!-- MESSAGES: defines the data being exchanged between the service and client -->
  <wsdl:message name="MyServiceIn">
    <wsdl:part name="parameters" element="tns:SayHelloRequest"/>
  </wsdl:message>
  <wsdl:message name="MyServiceOut">
    <wsdl:part name="parameters" element="tns:SayHelloResponse"/>
  </wsdl:message>
  <!-- PORT TYPES: defines the complete communication operation (one way/round trip) -->
  <wsdl:portType name="MyServicePort">
    <!-- The operation name must be the same as the one specified in the service object -->
    <wsdl:operation name="sayHello">
      <wsdl:input message="tns:MyServiceIn"/>
      <wsdl:output message="tns:MyServiceOut"/>
    </wsdl:operation>
  </wsdl:portType>
  <!-- BINDING: provides details on how a portType operation will actually be transmitted -->
  <wsdl:binding name="MyServiceBinding" type="tns:MyServicePort">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sayHello">
      <soap:operation soapAction="sayHello" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <!-- SERVICE:  -->
  <wsdl:service name="MyService">
    <wsdl:port name="MyServicePort" binding="tns:MyServiceBinding">
      <soap:address location="http://localhost:8000/wsdl"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

client.js

代码语言:javascript
复制
const soap = require("soap");

const url = "http://localhost:8000/wsdl?wsdl";

soap.createClient(url, function (err, client) {
  if (err) {
    console.error(err);
  } else {
    client.sayHello({ name: "Cell" }, function (err, result) {
      if (err) {
        console.error(err);
      } else {
        console.log(result);
      }
    });
  }
});

启动服务:

代码语言:javascript
复制
$ node server.js
SOAP service listening at http://localhost:8000/wsdl?wsdl

运行客户端脚本,可以看到输出:

代码语言:javascript
复制
$ node client.js
{ msg: [ 'Hello Cell!' ] }

服务端输出:

代码语言:javascript
复制
info Handling GET on /wsdl?wsdl
info Wants the WSDL
info Handling POST on /wsdl
received <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:tns="http://tempuri.org/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"><soap:Body><SayHelloRequest xmlns="http://tempuri.org/"><name>Cell</name></SayHelloRequest></soap:Body></soap:Envelope>
info Attempting to bind to /wsdl
info Trying MyServicePort from path /wsdl
replied <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"  xmlns:tns="http://tempuri.org/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"><soap:Body><SayHelloResponse xmlns="http://tempuri.org/"><msg>Hello Cell!</msg></SayHelloResponse></soap:Body></soap:Envelope>

# 优点

  • 独立于任何编程语言和操作系统
    • SOAP 使用 XML 作为消息格式,这使得它可以在不同的编程语言和操作系统之间进行通信
  • 标准化
    • SOAP 是一个开放标准,由多个组织共同开发和维护,这使得它具有广泛的支持和可靠性
  • 安全性高
    • SOAP 支持多种安全协议,例如 SSL/TLS 和 WS-Security,可以保证通信的机密性和完整性
  • 支持多种协议
    • SOAP 可以基于多种协议进行传输,例如 HTTP、SMTP 和 TCP,这使得它非常灵活

# 缺点

  • 复杂性高
    • SOAP 的 XML 消息格式和严格的规范要求使得它的开发和维护成本较高
  • 性能低
    • SOAP 的消息体较大,由于需要进行 XML 解析和序列化等操作,使得其性能比较低,特别是在数据量较大的情况下
  • 不适合简单的数据交换
    • SOAP 通常用于复杂的数据交换场景
    • 如企业级应用程序间的数据交换,对于简单的数据交换场景,SOAP 的复杂性可能不适用

# 适用场景

  • 企业级应用程序
    • SOAP 通常用于企业级应用程序之间的数据交换
    • 如不同的企业资源计划(ERP)系统之间的数据交换,或者不同的客户关系管理(CRM)系统之间的数据交换
  • Web 服务
    • SOAP 是一种基于 XML 的 Web 服务协议,可以用于开发复杂的 Web 服务
    • 如在线支付、订单处理、数据同步等
  • 跨平台应用程序
    • 由于 SOAP 不依赖于任何特定的编程语言和操作系统,因此它可以用于跨平台的应用程序
    • 如通过 SOAP 实现跨平台的移动应用程序和 Web 应用程序之间的数据交换

SOAP API 适用于需要高安全性和复杂数据交换的企业级应用程序和 Web 服务场景,但在简单数据交换场景下,可能过于复杂和性能不足。如果需要进行简单的数据交换,可以考虑使用 REST API 或其他更轻量级的协议。

# RESTful

RESTful API (Representational State Transfer API) 是一种基于 HTTP 协议的 Web API,它使用 HTTP 请求来对资源进行操作,如 GET、POST、PUT、DELETE 等,这些操作分别对应着对资源的查询、创建、更新和删除。

  • 资源
    • 将所有的数据视为资源,每个资源都有一个唯一的标识符
  • 表示
    • 使用某种媒体类型(例如 JSON 或 XML)来表示资源的状态
  • 状态转移
    • 使用 HTTP 方法(例如 GET、POST、PUT、DELETE)来表示对资源进行的操作
  • 无状态
    • RESTful API 是无状态的,每个请求都是独立的,服务器不会保存客户端的状态信息

# DEMO

server.js

代码语言:javascript
复制
const express = require("express");
const bodyParser = require("body-parser");

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

const port = process.env.PORT || 3000;

let users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
];

// GET /api/users
app.get("/api/users", (req, res) => {
  res.json(users);
});

// GET /api/users/:id
app.get("/api/users/:id", (req, res) => {
  const id = parseInt(req.params.id);
  const user = users.find((u) => u.id === id);
  if (user) {
    res.json(user);
  } else {
    res.status(404).send("User not found");
  }
});

// POST /api/users
app.post("/api/users", (req, res) => {
  const user = req.body;
  user.id = users.length + 1;
  users.push(user);
  res.json(user);
});

// PUT /api/users/:id
app.put("/api/users/:id", (req, res) => {
  const id = parseInt(req.params.id);
  const user = users.find((u) => u.id === id);
  if (user) {
    user.name = req.body.name;
    res.json(user);
  } else {
    res.status(404).send("User not found");
  }
});

// DELETE /api/users/:id
app.delete("/api/users/:id", (req, res) => {
  const id = parseInt(req.params.id);
  const index = users.findIndex((u) => u.id === id);
  if (index >= 0) {
    users.splice(index, 1);
    res.json({ message: "User deleted successfully" });
  } else {
    res.status(404).send("User not found");
  }
});

app.listen(port, () => {
  console.log(`Server is listening on port ${port}`);
});

client.js

代码语言:javascript
复制
const axios = require("axios");

const apiUrl = "http://localhost:3000/api";

// 获取所有用户列表
axios
  .get(`${apiUrl}/users`)
  .then((response) => {
    console.log("All users:", response.data);
  })
  .catch((error) => {
    console.error("Failed to get users:", error.message);
  });

// 获取指定用户信息
axios
  .get(`${apiUrl}/users/1`)
  .then((response) => {
    console.log("User 1:", response.data);
  })
  .catch((error) => {
    console.error("Failed to get user 1:", error.message);
  });

// 创建一个新用户
axios
  .post(`${apiUrl}/users`, { name: "David" })
  .then((response) => {
    console.log("New user:", response.data);
  })
  .catch((error) => {
    console.error("Failed to create user:", error.message);
  });

// 更新指定用户信息
axios
  .put(`${apiUrl}/users/1`, { name: "Alice Smith" })
  .then((response) => {
    console.log("Updated user 1:", response.data);
  })
  .catch((error) => {
    console.error("Failed to update user 1:", error.message);
  });

// 删除指定用户
axios
  .delete(`${apiUrl}/users/1`)
  .then((response) => {
    console.log("Deleted user 1:", response.data);
  })
  .catch((error) => {
    console.error("Failed to delete user 1:", error.message);
  });

启动服务

代码语言:javascript
复制
$ node server.js

Server is listening on port 3000

运行客户端

代码语言:javascript
复制
$ node client.js

All users: [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
]
User 1: { id: 1, name: 'Alice' }
New user: { name: 'David', id: 4 }
Updated user 1: { id: 1, name: 'Alice Smith' }
Deleted user 1: { message: 'User deleted successfully' }

# 优点

  • 简单性
    • 设计原则简单明了,易于理解和实现
  • 可读性
    • URL 结构和 HTTP 方法表示操作,使其易于阅读和理解
  • 可扩展性
    • 设计原则允许系统的组件可以独立演化,使得系统具有较高的可扩展性
  • 灵活性
    • 可以使用多种媒体类型、支持多种协议,使得它非常灵活
  • 可缓存性
    • 支持缓存机制,可以减少服务器的负载,提高性能

# 缺点

  • 标准化不足
    • 设计原则比较灵活,缺乏标准化规范,可能会导致不同的实现方式之间存在差异
  • 安全性较低
    • 由于 RESTful API 是无状态的,缺乏安全性和验证机制,可能会导致安全性问题
  • 难以处理复杂逻辑
    • 对于复杂的业务逻辑和数据处理,RESTful API 可能不够灵活,需要使用其他技术或协议

# 适用场景

  • Web 应用程序
    • 可以用于构建 Web 应用程序
    • 如在线商店、社交网络和博客等
  • 移动应用程序
    • 可以用于构建移动应用程序
    • 如移动购物应用、社交应用和游戏应用等
  • 云服务
    • 可以用于构建云服务
    • 如云存储、云计算和云数据库等
  • IoT(物联网)应用程序
    • 可以用于物联网设备和应用程序之间的通信
    • 如智能家居、智能城市和智能工厂等
  • 微服务
    • RESTful API 是构建微服务架构的重要组成部分,可以将不同的服务组合在一起,构建出高度可扩展和灵活的系统

对于大部分的应用程序,RESTful API 是一种非常合适的选择,它具有简单、灵活、可扩展等优点,可以用于开发大部分的 Web 服务和移动应用程序。但对于需要实时性要求较高的应用程序,或者需要处理复杂的业务逻辑和数据处理的应用程序,可能需要使用其他技术或协议。

# GraphQL

GraphQL 是一种用于 API 开发的查询语言和运行时环境。它由 Facebook 于 2012 年开发,于 2015 年作为开源项目发布。

GraphQL 可以让客户端精确地指定其需要的数据,而不必取回 API 提供的全部数据。这样可以减少不必要的网络请求和数据传输,提高应用程序的性能和可扩展性。

# DEMO

server.js

代码语言:javascript
复制
const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");

// 定义 schema
const schema = buildSchema(`
  type Product {
    id: ID!
    name: String!
    description: String!
    price: Float!
  }

  type Order {
    id: ID!
    products: [Product!]!
    total: Float!
  }

  type Query {
    product(id: ID!): Product
    products: [Product!]!
    order(id: ID!): Order
    orders: [Order!]!
  }

  type Mutation {
    createOrder(productIds: [ID!]!): Order
    cancelOrder(id: ID!): Order
  }
`);

// 模拟数据
const products = [
  { id: "1", name: "iPhone", description: "Apple iPhone", price: 999 },
  { id: "2", name: "iPad", description: "Apple iPad", price: 799 },
  { id: "3", name: "MacBook", description: "Apple MacBook", price: 1299 },
];

const orders = [];

// 定义 resolver
const root = {
  // 查询单个商品
  product: ({ id }) => {
    return products.find((product) => product.id === id);
  },

  // 查询所有商品
  products: () => {
    return products;
  },

  // 查询单个订单
  order: ({ id }) => {
    return orders.find((order) => order.id === id);
  },

  // 查询所有订单
  orders: () => {
    return orders;
  },

  // 创建订单
  createOrder: ({ productIds }) => {
    const selectedProducts = products.filter((product) => productIds.includes(product.id));
    const total = selectedProducts.reduce((acc, product) => acc + product.price, 0);
    const order = { id: orders.length + 1, products: selectedProducts, total };
    orders.push(order);
    return order;
  },

  // 取消订单
  cancelOrder: ({ id }) => {
    const index = orders.findIndex((order) => order.id === id);
    if (index === -1) {
      throw new Error(`Order with id ${id} not found`);
    }
    const order = orders[index];
    orders.splice(index, 1);
    return order;
  },
};

// 创建 express app
const app = express();

// 添加 graphql 中间件
app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true,
  })
);

// 监听端口
app.listen(3000, () => {
  console.log("GraphQL server running at http://localhost:3000/graphql");
});

启动服务

代码语言:javascript
复制
$ node server.js

GraphQL server running at http://localhost:3000/graphql

服务启动后,可以在浏览器中访问 http://localhost:3000/graphql,打开 GraphQL Playground,可以在 Playground 中进行 GraphQL 查询和操作。

如,查询所有商品

代码语言:javascript
复制
{
  products {
    id
    name
    description
    price
  }
}

这个查询会返回所有商品的列表,并包含每个商品的 ID、名称、描述和价格。

也可以通过以下查询来获取单个商品的信息:

代码语言:javascript
复制
{
  product(id: "1") {
    id
    name
    description
    price
  }
}

也可以使用以下查询来创建一个新订单:

代码语言:javascript
复制
mutation {
  createOrder(productIds: ["1", "2"]) {
    id
    products {
      id
      name
      price
    }
    total
  }
}

# 优点

  • 灵活性
    • GraphQL 的查询语言可以自定义数据返回的形式和内容
    • 客户端可以精确地指定需要的数据,减少了网络传输和 API 请求的数量,提高了性能和效率
  • 可扩展性
    • 支持可扩展的架构,可以轻松地添加新的字段和类型,而不会破坏现有的 API
  • 可组合性
    • 支持混合和嵌套多个查询
    • 可以将多个查询组合成一个请求,减少了网络传输和 API 请求的数量
  • 自描述性
    • GraphQL 具有自描述性,可以描述可用的查询字段和类型,使得客户端可以轻松地了解 API 的功能和数据模型

# 缺点

  • 学习成本
    • 相比传统的 REST API,GraphQL 有更高的学习成本,需要掌握新的查询语言和 API 设计方法
  • 缓存
    • GraphQL 的灵活性和可扩展性使得缓存变得更加复杂,需要使用专门的缓存机制来提高性能
  • 安全性
    • 由于 GraphQL 的灵活性,如果没有正确的安全措施,可能会导致数据泄漏和安全漏洞

# 适用场景

  • 移动应用程序
    • GraphQL 可以减少网络请求和数据传输量,提高移动应用程序的性能和效率。
  • 大型 Web 应用程序
    • GraphQL 的可扩展性和灵活性使得它适用于需要处理大量数据的 Web 应用程序
    • 如 Facebook、GitHub 等都在使用 GraphQL,以此来提高性能和可扩展性
  • 微服务
    • 可以作为微服务架构的一部分,通过定义清晰的 API 接口来简化服务之间的通信

# gRPC

gRPC 是一个高性能、开源的远程过程调用(RPC)框架,由 Google 开发。

该框架使用 Protocol Buffers 作为接口定义语言(IDL),并支持多种编程语言,例如 C++、Java、Python、Go 等。gRPC 提供了基于 HTTP/2 的通信协议,可以实现双向流、请求/响应语义和头部压缩等功能。

# DEMO

sercer1.js

代码语言:javascript
复制
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");

// 加载Proto文件
const packageDefinition = protoLoader.loadSync("./calculator.proto", {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});

// 加载服务定义
const calculatorProto = grpc.loadPackageDefinition(packageDefinition).calculator;

// 实现服务端方法
function add(call, callback) {
  const { a, b } = call.request;
  const result = a + b;
  callback(null, { result });
}

function subtract(call, callback) {
  const { a, b } = call.request;
  const result = a - b;
  callback(null, { result });
}

// 创建gRPC服务器
const server = new grpc.Server();

// 添加服务
server.addService(calculatorProto.Calculator.service, {
  Add: add,
  Subtract: subtract,
});

// 启动服务器
server.bindAsync("localhost:50051", grpc.ServerCredentials.createInsecure(), () => {
  server.start();
  console.log("gRPC server running at http://localhost:50051");
});

calculator.proto

代码语言:javascript
复制
syntax = "proto3";

package calculator;

service Calculator {
  rpc Add(AddRequest) returns (AddResponse) {}
  rpc Subtract(SubtractRequest) returns (SubtractResponse) {}
}

message AddRequest {
  int32 a = 1;
  int32 b = 2;
}

message AddResponse {
  int32 result = 1;
}

message SubtractRequest {
  int32 a = 1;
  int32 b = 2;
}

message SubtractResponse {
  int32 result = 1;
}

sercer2.js

代码语言:javascript
复制
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");

const packageDefinition = protoLoader.loadSync("./calculator.proto", {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});

const calculatorProto = grpc.loadPackageDefinition(packageDefinition).calculator;

const client = new calculatorProto.Calculator("localhost:50051", grpc.credentials.createInsecure());

function runCalculator() {
  const a = 10;
  const b = 5;

  // 调用 Add 方法
  client.Add({ a, b }, (err, response) => {
    if (err) {
      console.error(err);
      return;
    }

    console.log(`Add Result: ${response.result}`);
  });

  // 调用 Subtract 方法
  client.Subtract({ a, b }, (err, response) => {
    if (err) {
      console.error(err);
      return;
    }

    console.log(`Subtract Result: ${response.result}`);
  });
}

runCalculator();

启动服务 1

代码语言:javascript
复制
$ node server1.js

gRPC server running at http://localhost:50051

启动服务 2

代码语言:javascript
复制
$ node server2.js

Add Result: 15
Subtract Result: 5

# 优点

  • 高效性
    • 使用 Protocol Buffers 作为 IDL,这使得它非常高效
      • Protocol Buffers 是一种高效的二进制序列化格式,可以将数据序列化为二进制码,从而减少了数据传输的大小和传输时间
    • 使用 HTTP/2 作为通信协议,可以实现双向流和头部压缩等功能,从而提高了性能
  • 可扩展性
    • 支持多种编程语言,可以在不同的平台和语言之间进行通信
    • 支持流式处理和服务端流式响应,可以处理大量的数据传输和处理
  • 易用性
    • 提供了自动生成代码的工具,可以根据 IDL 自动生成客户端和服务端的代码,使得开发人员可以更加轻松地使用和开发 gRPC 服务
    • 提供了丰富的文档和示例,可以帮助开发人员快速上手

# 缺点

  • 学习成本高
    • 使用 Protocol Buffers 作为 IDL,需要对其进行学习和掌握
    • 需要了解 HTTP/2 协议和流式处理等概念
    • 对于不熟悉这些概念的开发人员来说,学习成本可能会比较高
  • 不支持 RESTful API
    • 采用 RPC 的方式进行通信,不支持基于 HTTP 的 RESTful API
    • 如果需要使用 RESTful API,需要使用其他的框架

# 适用场景

  • 微服务架构
    • 适用于微服务架构中的服务间通信,可以实现高效、可扩展的服务间通信
  • 高并发场景
    • 使用 HTTP/2 协议和流式处理等技术,可实现高效的并发处理,适用于高并发场景
    • 如实时通信、数据处理和分布式计算等
  • 跨平台通信
    • gRPC 支持多种编程语言和平台,可以在不同的语言和平台之间进行通信,适用于异构的系统和跨平台通信场景

举例来说,Google 的基础设施中广泛使用 gRPC,例如 Google Cloud、YouTube、Google 搜索等。另外,Uber 也使用了 gRPC 来构建其微服务架构,通过 gRPC 实现服务间通信,提高了系统的性能和可扩展性。

# WebSocket

WebSocket 是一种在客户端和服务器之间建立双向通信的协议,它基于 TCP 协议实现,可以在单个 TCP 连接上提供全双工通信功能,使得客户端和服务器可以实时地交换数据。

# DEMO

server.js

代码语言:javascript
复制
// 引入 ws 模块
const WebSocket = require("ws");

// 创建 WebSocket 服务器
const server = new WebSocket.Server({ port: 8080 });

// 监听连接事件
server.on("connection", (socket) => {
  console.log("客户端已连接");

  // 向客户端发送消息
  socket.send("欢迎连接 WebSocket 服务器");

  // 监听客户端发来的消息
  socket.on("message", (message) => {
    console.log(`收到客户端消息:${message}`);

    // 回复客户端消息
    socket.send(`服务器已收到消息:${message}`);
  });
});

// 输出服务器启动信息
console.log("WebSocket 服务器已启动,监听端口 8080");

client.js

代码语言:javascript
复制
// 引入 ws 模块
const WebSocket = require("ws");

// 创建 WebSocket 客户端
const socket = new WebSocket("ws://localhost:8080");

// 监听连接成功事件
socket.addEventListener("open", (event) => {
  console.log("已连接到 WebSocket 服务器");

  // 向服务器发送消息
  socket.send("你好,WebSocket 服务器");
});

// 监听收到服务器消息事件
socket.addEventListener("message", (event) => {
  console.log(`收到服务器消息:${event.data}`);
});

// 监听连接关闭事件
socket.addEventListener("close", (event) => {
  console.log("WebSocket 连接已关闭");
});

// 监听连接错误事件
socket.addEventListener("error", (event) => {
  console.log("WebSocket 连接发生错误");
});

# 优点

  • 实时性
    • 可以提供实时的双向通信,无需客户端不断地向服务器发送请求,服务器也可以主动推送数据给客户端,从而实现实时的数据交换
  • 低延迟
    • 由于 WebSocket 建立的是长连接,减少了连接建立和断开的开销,从而降低了通信的延迟
  • 更少的数据传输量
    • 由于 WebSocket 不需要在每次通信时都发送 HTTP 请求头和响应头,因此可以减少数据传输量,降低网络带宽占用,提高通信效率
  • 跨域支持
    • WebSocket 可以跨域通信,可以在不同的域名下建立连接,从而实现更加灵活的应用场景

# 缺点

  • 对于低版本浏览器的兼容性问题
    • WebSocket 是 HTML5 的一部分,因此只能在支持 HTML5 的浏览器中使用
    • 对于一些较老的浏览器或移动设备,可能无法很好地支持 WebSocket
  • 对于服务器资源的占用
    • WebSocket 需要维持长连接,因此可能会占用较多的服务器资源
    • 在高并发的情况下,需要考虑服务器的负载和性能问题
  • 安全性问题
    • WebSocket 在传输数据时,需要使用 SSL/TLS 加密协议保证数据的安全性
    • 如果没有正确配置 SSL/TLS,可能会存在数据被篡改或窃取的风险
  • 跨域限制问题
    • 由于浏览器的同源策略限制,WebSocket 在跨域访问时可能会遇到一些问题
    • 需要在服务器端进行相应的配置,才能实现跨域访问

# 适用场景

  • 实时通信
    • 可以用于实时通信场景
    • 如在线聊天、在线游戏、在线视频会议等,可以实现实时的数据交换和即时响应
      • 在线游戏中,客户端和服务器需要实时交换游戏信息,如玩家位置、游戏状态等,WebSocket 可以提供实时、低延迟的通信服务,从而提升游戏体验
  • 数据推送
    • 可以用于数据推送场景
    • 如股票行情、天气预报等,可以实时地将数据推送给客户端,客户端可以根据推送的数据进行相应的处理
  • 实时协作
    • 可以用于实时协作场景
    • 如团队协作、远程教育等,可以实现多人之间的实时协作和交流

需要注意的是,WebSocket 对于一些非实时通信的场景可能不太适用,因为它需要建立长连接,并且需要保持连接状态,这可能会占用较多的服务器资源。此外,WebSocket 也需要客户端和服务器端都支持该协议,因此在一些老旧的浏览器或服务器上可能无法正常使用。因此,在选择使用 WebSocket 时需要根据具体的应用场景进行评估和选择。

# Webhook

Webhook 是一种 HTTP 回调机制,它允许应用程序之间实时通信,以便在特定事件发生时自动触发某些操作。具体来说,Webhook 允许应用程序将 HTTP POST 请求发送到指定的 URL,以通知接收方某个事件已发生。Webhook 通常用于自动化工作流程、实时数据同步、实时通知等场景。

典型的应用场景,如在 Github 中 Webhook 可以用于执行自动化测试、自动化部署等操作,当代码仓库中的代码发生变更时,可以自动触发 Webhook,从而执行相应的操作。

# DEMO

假设我们有一个在线商店,当有新订单时,我们需要将订单数据同步到第三方财务系统中。我们可以使用 Node.js 实现一个 Webhook 应用程序来实现这个功能。

server.js

代码语言:javascript
复制
const express = require("express");
const bodyParser = require("body-parser");
const app = express();

// 使用body-parser中间件解析POST请求体
app.use(bodyParser.json());

// 处理Webhook请求
app.post("/webhook", (req, res) => {
  const orderData = req.body;

  // 将订单数据同步到第三方财务系统中
  syncOrderDataToFinanceSystem(orderData);

  // 响应Webhook请求
  res.send("Webhook received");
});

// 启动服务器
app.listen(3000, () => {
  console.log("Webhook server started on port 3000");
});

// 将订单数据同步到第三方财务系统中
function syncOrderDataToFinanceSystem(orderData) {
  // 在这里编写将订单数据同步到第三方财务系统的代码
  console.log("Order data synced to finance system:", orderData);
}

client.js

代码语言:javascript
复制
const axios = require("axios");

const postData = {
  orderId: "123456",
  customerName: "John Doe",
  totalPrice: 100.0,
};

// 发送Webhook请求
axios
  .post("http://localhost:3000/webhook", postData)
  .then((response) => {
    console.log(`Webhook server responded with status code: ${response.status}`);
    console.log(`Response from webhook server: ${response.data}`);
  })
  .catch((error) => {
    console.error(`Error while sending webhook request: ${error}`);
  });

# 优点

  • 实时性
    • 可以实现实时通信,即时触发相关操作
  • 可靠性
    • 具有高可靠性,因为它是通过 HTTP 协议发送的,可以通过 HTTP 状态码来检测是否成功发送
  • 简单易用
    • 实现非常简单,只需要一个 HTTP POST 请求即可

# 缺点

  1. 安全性:Webhook 需要暴露一个 URL,如果没有足够的安全措施,可能会受到恶意攻击。
  2. 可扩展性:Webhook 机制的可扩展性受到限制,因为每个 Webhook 都需要指定一个 URL,如果要扩展到大量的事件和接收方,可能需要多个 URL,这会导致管理困难。

# 适用场景

  • 自动化工作流程
    • 可以用于在应用程序之间自动触发某些操作
    • 如将新的客户数据同步到 CRM 系统中
  • 实时数据同步
    • 可以用于在应用程序之间实时同步数据
    • 如将新的订单数据同步到财务系统中
  • 实时通知
    • 可以用于实现实时通知
    • 如将重要事件通知到相关人员

Webhook 最适合的场景是需要实时响应的场景,比如需要立即处理某些事件或发送实时通知的场景。此外,Webhook 还适用于需要在应用程序之间自动化触发某些操作的场景,例如将数据同步到不同的系统中。但是,如果安全性是一个问题,或者需要扩展到大量的事件和接收方,可能需要考虑其他方案。

# Demo 代码

exploring-the-top-6-most-popular-api-architecture-styles (opens new window)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023/4/2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 前言
  • # SOAP
    • # DEMO
      • # 优点
        • # 缺点
          • # 适用场景
          • # RESTful
            • # DEMO
              • # 优点
                • # 缺点
                  • # 适用场景
                  • # GraphQL
                    • # DEMO
                      • # 优点
                        • # 缺点
                          • # 适用场景
                          • # gRPC
                            • # DEMO
                              • # 优点
                                • # 缺点
                                  • # 适用场景
                                  • # WebSocket
                                    • # DEMO
                                      • # 优点
                                        • # 缺点
                                          • # 适用场景
                                          • # Webhook
                                            • # DEMO
                                              • # 优点
                                                • # 缺点
                                                  • # 适用场景
                                                  • # Demo 代码
                                                  相关产品与服务
                                                  Serverless HTTP 服务
                                                  Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
                                                  领券
                                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档