WEB API 设计规范

REST API 简介

REST 是 Representational State Transfer 的缩写,它将资源作为核心概念,通过 HTTP 方法对资源进行操作。其本身是一套围绕资源进行操作的架构规范。在实际应用中,更多的是体现在 API 的设计上。

企业在进行产品设计开发时,通常首先由业务专家和技术专家一起梳理出业务模型,然后根据领域驱动设计(DDD)的方法论进行建模,设计出领域模型以及针对领域模型的操作。最终,这些领域模型会映射为数据存储的数据模型以及 REST API 的资源模型,而针对领域模型的操作会映射为 HTTP 方法以及 REST API 的 Action。

REST API 几乎已经是互联网服务 Web API 设计的事实标准,根据 Google 的 API 设计指南,早在 2010 年,就有大约 74% 的公共网络 API 是 HTTP REST(或类似 REST)风格的设计,大多数 API 均使用 JSON 作为传输格式。

RESTful 设计原则

满足 REST 要求的架构需遵循以下6个设计原则:

1. 客户端与服务端分离

目的是将客户端和服务端的关注点分离。在 Web 应用中,将用户界面所关注的逻辑和服务端数据存储所关注的逻辑分离开来,有助于提高客户端的跨平台的可移植性;也有助于提高服务端的可扩展性。

随着前端技术的发展,前后端分离已经是主流的开发方式,传统的 Spring MVC/Django 的前端模板渲染已经被逐渐弃用了。

2. 无状态

服务端不保存客户端的上下文信息,会话信息由客户端保存,服务端根据客户端的请求信息处理请求。

在实际开发中,服务端通常会保存一些状态信息,比如会话信息、认证信息等,这些信息一般是保存在服务端的数据库或者缓存中。

3. 可缓存

这一条算是上一条的延伸,无状态服务提升了系统的可靠性、可扩展性,但也会造成不必要的网络开销。为了缓解这个问题,REST 要求客户端或者中间代理(网关)能缓存服务端的响应数据。服务端的响应信息必须明确表示是否可以被缓存以及缓存的时长,以避免客户端请求到过期数据。

管理良好的缓存机制可以有效减少客户端-服务器之间的交互,甚至完全避免客户端-服务器交互,从而提升了系统的性能和可扩展性。

4. 分层系统

对于客户端来说,中间代理是透明的。客户端无需知道请求路径中代理、网关、负载均衡等中间件的存在,这样可以提高系统的可扩展性和安全性。

5. 统一接口

REST 要求开发者面向资源来设计系统,有下面四个约束:

  • 每次请求中都包含资源 ID

  • 所有操作均等通过资源 ID 进行

  • 消息是自描述的:每条消息包含足够的信息来描述如何处理这条消息。比如 mime 标识媒体类型,content-type 标识编码格式,language 标识语言,charset 标识字符集,encoding 标识压缩格式等。

  • 用超媒体驱动应用状态(HATEOAS,Hypermedia as the Engine of Application State):客户端在访问了最初的 REST API 后,服务端会返回后续操作的链接,客户端使用服务端提供的链接动态的发现可用资源和可执行操作。

6. 按需编码(可选)

这是一条可选约束,指的是服务端可以根据客户端需求,将可执行代码发送给客户端,从而实现临时性的功能扩展或定制功能,比如以前的 Java Applet。

REST API 成熟度模型

上述约束读起来还是有些抽象,鉴于在实际开发中,我们更多是聚焦在 API 设计上。为了衡量一个系统是否符合 REST 风格,《RESTful Web APIs》和《RESTful Web Services》的作者 Leonard Richardson 提出了 REST 成熟度模型,根据 API 的设计风格将其分为了 4 级。

第 0 级: 完全不符合 REST 风格

比如 RPC 面向过程的 API 设计基本是围绕操作过程来设计的,完全没有资源的概念。

下面是 Martin Fowler 在介绍成熟度模型的 blog Richardson Maturity Model 中举的病人预约的例子,病人首先需要查询医生可预约的时间表,然后提交预约。

查询预约服务时提交的请求为

POST /appointmentService?action=query HTTP/1.1{"date": "2020-03-04","doctor": "mjones"
}

请求成功后响应如下

HTTP/1.1 200 OK
[{"start": "14:00","end": "14:50","doctor": "mjones"},{"start": "16:00","end": "16:50","doctor": "mjones"}
]

然后病人选择时段提交预约

POST /appointmentService?action=confirm HTTP/1.1{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"}
}

预定成功时响应如下

HTTP/1.1 200 OK{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"}
}

预定失败时响应如下

HTTP/1.1 200 OK{"slot": {"start": "14:00","end": "14:50","doctor": "mjones"},"patient": {"id": "jsmith"},"reason": "Slot not available"
}

可以看到整个请求过程没有涉及到资源的概念,并且请求也比较简洁明了。但如果操作越来越多,接口也越来越多,随之而来的维护、沟通成本也会越来越高。

第 1 级:引入资源概念

引入资源后,对服务端的访问都是围绕资源,通过资源 ID 进行。此时的查询和预约请求如下:

查询预约:以医生为资源,通过 ID查询

POST /doctors/mjones HTTP/1.1{date: "2020-03-04"}// 请求响应[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50"},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}
]

提交预约时,以时间表 slot 为资源,通过 ID 预约

POST /slots/1234 HTTP/1.1{ "patient_id": "jsmith" }
第 2 级:操作映射到 HTTP 方法

上面的例子中所有请求都是用的 POST 方法,Level2 要求将操作映射到 HTTP 方法。对于资源的操作无非就是增删改查,HTTP 对应的 POST、DELETE、PUT/PATCH、GET 可以很好的表达这些操作。

  • 查询档期,使用 GET 方法
GET /doctors/mjones/schedule?date=2020-03-04&status=open HTTP/1.[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50"},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}
]
  • 创建预约,使用 POST 方法
POST /schedules/1234 HTTP/1.1{ "patient_id": "jsmith" }
// 预定成功响应
HTTP/1.1 201 Created
Location: slots/1234/appointment{"slot": {"id": 1234,"doctor": "mjones","start": "14:00","end": "14:50"},"patient": {"id": "jsmith"}
}

预定失败时,需要返回能表达错误原因的响应码,而不是像之前一样返回 200。

HTTP/1.1 409 Conflict[{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50"}  
]

第2级是目前绝大多数系统所达到的级别。

第 3 级:状态转移完全由后端驱动

在实际开发中,通常是客户端和服务端约定好 API 后进行各自的实现。客户端在代码中已经编写了 API 相关的调用,但 REST 认为这是多余的,客户端应该根据服务端返回的链接进行后续操作,返回的资源信息以及操作链接信息能够描述自身以及后续可能发生的状态转移,从而实现超文本驱动应用状态。

依然是查询预约的 API,此时后端返回的预约列表,除了基本信息外还带有预约所需 link,由此客户端知晓后续的预约操作,并请求服务端返回的 link 进行操作。

GET /doctors/mjones/slots?date=20100104&status=open HTTP/1.1[{"slot_id": 1234, doctor: "mjones", start: "14:00", end: "14:50", links: [{"rel": "book", "href": "/slots/1234"}]},{"slot_id": 5678, doctor: "mjones", start: "16:00", end: "16:50", links: [{"rel": "book", "href": "/slots/5678"}]}
]

可以看到返回的数据中包含了支持的预约操作以及操作所对应的链接。

REST VS RPC

API 的设计通常有 RPC 和 REST 两种形式。虽然两者并不是一回事,但因为都是面向服务端和客户端的通信制定规范,所以经常被混为一谈。

REST 本身一套面向资源的架构设计思想,而 RPC 的初衷是希望能在分布式系统之间,像调用本地方法一样调用远程方法,围绕通信过程实现进行的一系列实现。RPC 协议也是层出不穷,针对数据的编码、传输以及方法的表达提供不同的解决方案。关于 RPC 更多的讲解可以参考凤凰架构:远程服务调用。

具体到 API 设计上,其主要区别在于:REST 是面向资源的,而 RPC 是面向过程的。以一个用户的增删改查为例,REST 的 API 设计如下

# 创建用户
POST /users
# 查询用户列表
GET /users  
# 查询用户详情
GET /users/{id}
# 更新用户信息
PUT /users/{id}
# 删除用户
DELETE /users/{id}

而 RPC 的 API 设计如下:

# 创建用户
POST /createUser
# 查询用户列表
GET /getUserList
# 查询用户详情
GET /getUserById
# 更新用户信息
PUT /updateUser
# 删除用户
DELETE /deleteUser

URI 的设计规范

了解了 REST API 的一些基本概念,下面我们看下可以在实践中应用的 URI设计规范。

根据 RFC 3986 - - Uniform Resource Identifier (URI): Generic Syntax 中的定义,一个 URI 的结构如下所示:

       foo://example.com:8042/over/there?name=ferret#nose\_/   \______________/\_________/ \_________/\__/|        |              |          |          |
scheme(协议)authority(域名) path(路径) query(查询参数)fragment(片段)

我们这里主要针对 path 和 query 部分进行讨论,对于 PATH 我们可以使用如下规范形式:

{domain}/{version}/{appid}/{resource}
{domain}/{version}/{appid}/{resource}/{sub-resource}/
{domain}/{version}/{appid}/{resource}/{action}

URI 主体字段含义

首先来看下 URL 中各个字段的含义与设计规范。

  • {domain} 表示 API 的域名。可以使用统一的域名,也可以针对不同的业务线使用不同的域名。
  • {version} 表示 API 的版本。形式是 v + 数字,比如 v1, v2,有特殊需求是也可以进一步区分主版本和子版本,比如 v1.1, v1.2。一般只有在接口不兼容时才会升级。
  • {appid} 服务的唯一标识。比如 order 表示订单服务,user 表示用户服务,payment 表示支付服务。
  • {resource} 具体的资源,要用名词且为复数形式。比如 orders 表示订单资源,users 表示用户资源,payments 表示支付资源。
  • {sub-resource} 子资源,操作场景下和资源有依赖关系,要用名词且为复数形式。比如购物车和购物车项。
  • {action} 针对资源或子资源的行为操作,用动词或者动词短语表示,用来弥补 HTTP 方法表达上的不足。

URI 路径规范

1. URI 中所有命名必须是小写英文

下面是一个不规范的实例,使用了大写字或非英文字母。

https://api.server.com/v1/订单/orders 
https://api.server.com/v1/PAYMENT/records
https://api.server.com/v1/order/orders/REFUND
2. URI 路径分隔符推荐使用中划线 -

下面是一个使用 _ 的不规范实例

https://api.server.com/v1/marketing/coupons/get_by_code
3. URI 路径中查询参数命名必须统一使用 snake_case 或 camelCase 风格

在实践中笔者通常倾向于统一使用 snake_case 风格,但有的团队也会使用驼峰命名法。这里重要的是保持统一,避免在进行 API 设计时因为风格不一致导致不必要的沟通成本。

下面是一个使用 snake_case 风格的 URI:

https://api.server.com/v1/marketing/coupons/get-by-merchants?merchant_id=123456

下面是一个使用 camelCase 风格的 URI:

https://api.server.com/v1/marketing/coupons/getByMerchants?merchantId=123456

下面是一个使用驼峰命名法的不规范 URI,首字母用了大写:

https://api.server.com/v1/marketing/coupons/get-by-merchants?MerchantId=123456
4. URI 中禁止出现 CURD 动词,应该映射到 HTTP 方法

下面是一个不合法的 URI 示例,使用了 CURD 动词:

GET /doctors/mjones/get-schedules

如果有特殊需求,应该有更明确的语义表达,但 Get、List、Update、Delete 这些 CURD 应该尽量避免。

5. URI 的路径和参数必须以标准 UTF-8 编码

比如出现汉字、空格、特殊符号等字符时,需要进行编码。

6. URI 长度限制

RFC7230 中并没有对 URI 的长度进行限制,但在实际开发中,最好限制在 2048 以内。如果 URI 过程,需要返回 HTTP 414 状态码(URI Too Long)。[参考 Stackoverflow]。

7. 资源 ID 规范

资源 ID 必须放到资源的后面,并且尽可能使用 UUID、HMAC 等类型的 ID,而不是数据库的自增主键 ID,避免被人通过主键 ID 爬数据。比如

https://api.server.com/v1/payment/orders/298f37e-a538-11e9-93e8-0b39560ac73d
7. 子资源使用规范

只有在 API 操作场景下,子资源和资源有依赖关系时,才使用子资源。大致有两类情况:

  • 子资源不能独立存在,必须依附于上级主资源访问。比如某个用户的简历信息,必须依附在某个用户下。

  • 子资源不能独立表达含义。比如社交系统用的用户和好友资源。可能最终访问的是同一张数据表,但在用户操作场景下可以独立存在,而在好友场景下是依附于用户存在的。

  • 查询用户信息

# 查询用户详情
GET .../users/1# 查询用户简历信息
GET .../users/1/resume# 查询用户好友
GET .../users/1/friends

在使用子资源时需要注意嵌套层级,尽可能不要使用超过 3 层的嵌套。

  • 过多的嵌套会导致 API 过于复杂,不易理解
  • 多级资源容易导致 URI 过长,引起一些兼容性问题。
8. 动词使用规范

对资源的增删改查应该使用标准的 HTTP 方法,比如 GET、POST、PUT、DELETE。下面是 HTTP 方法于操作的映射关系:

REST API 要求对资源的操作应该与 HTTP 方法对应,下面是资源操作的标准方法与映射关系。

资源操作HTTP 方法描述是否幂等是否支持 Body响应格式
ListGET用于查询操作,对应数据库的 select 操作✔︎资源列表,无数据时返回空列表
GetGET用于查询操作,对应数据库的 select 操作✔︎资源详情,无数据时返回 404
UpdatePUT用于所有的信息更新,对应数据库的 update 操作✔︎✔︎资料详情
DeleteDELETE用于更新操作,对应数据库的 delete 操作✔︎
CreatePOST用于新增操作,对应数据库的 insert 操作✔︎资源详情
HEAD用于返回一个资源对象的“元数据”,或是用于探测API是否健康✔︎资源详情
UPDATEPATCH用于局部信息的更新,对应于数据库的 update 操作资源详情
OPTIONS获取API的相关的信息。✔︎

以下是基本的 API 示例

// 创建用户
POST /users//查询用户列表
GET /users// 查询用户详情
GET /users/1// 更新用户信息
PUT /users/1// 删除用户
DELETE /users/1

如果有特殊的动作可以在路径中使用 action 来标识,action 必须是动词性质的单词或短语。比如

# 实名认证
POST /users/1/real-name-auth# 取消订单
PUT /orders/123456/cancel# 激活优惠券
PUT /coupons/123456/activate

常用标准字段

API 中通常有许多通用字段,比如名称,排序,分页,时间戳等,下面是一些常用的标准字段和相关规范。

字段名类型说明
namestring资源名称
parentstring父资源名称
create_timetimestamp创建时间
create_bystring创建者
update_timetimestamp更新时间
update_bystring更新者
delete_timetimestamp删除时间
delete_bystring删除者
expire_timetimestamp过期时间
start_timetimestamp开始时间
end_timetimestamp结束时间
time_zonestring时区名称, 取值应遵从 Time Zone Database 中给出的时区名称
region_codestring地区编码,取值应遵从 unicode_region_subtag 标准
language_codestring语言编码,取值应遵从 Unicode_Language_and_Locale_Identifiers
currency_codestring货币编码,取值应遵从 ISO 4217 标准
mime_typestring媒体类型,取值应遵从 Mime 类型 标准
page_sizeint32分页大小
page_numberint32分页页码
total_sizeint32数据总数
total_pageint32数据总页数
sort/order_bystring排序字段
asc/descstring排序顺序
filterstring过滤器参数
and、or、not过滤器表达式要支持的逻辑操作符
=,!=,>,<,>=,<=过滤器表达式要支持的比较操作符,实际使用中有时也用单词表示:eq,ne,gt,lt,ge,le 表示
search/querystring搜索参数
sort_orderstring排序顺序,取值为 asc 或 desc
create_bystring创建者
update_bystring更新者
statusstring状态
remarkstring备注

HTTP 规范

Header 规范

应该尽可能使用标准的请求/响应头。以下是一些常用的标准请求头:

字段名类型说明
Content-Typestring请求体格式,比如 application/json
Acceptstring告诉服务器可以接收的内容类型,如:application/xml, text/xml, application/json, text/javascript (for JSONP, 大多数时候都是选择选择application/json)
Accept-Languagestring告诉服务器可以接收的语言,如:zh-CN, en-US
Accept-Encodingstring告诉服务器可以接收的编码,如:gzip, deflate
Accept-Charsetstring告诉服务器可以接收的字符集,如:utf-8, utf-16
Authorizationstring认证信息,取值为 Bearer token
Datestring客户端的时间戳,最好是 UTC 时间。但服务端不能依赖这个字段,因为客户端的时间可能不准确。

缓存相关 Header

字段名类型说明
Expiresstring告知客户端缓存过期时间,如果与 Cache-Control 同时出现,则以 Cache-Control 为准。
Cache-Controlstring缓存控制
Last-Modifiedstring告知客户端资源最后修改时间
If-Modified-Sincestring将 Last-Modified 的值发送给服务器,服务器判断资源是否被修改,如果被修改,则返回 200 状态码,否则返回 304(Not Modified) 状态码
ETagstring告知客户端资源的唯一标识
If-None-Matchstring将 ETag 的值发送给服务器,服务器判断资源是否被修改,如果被修改,则返回 200 状态码,否则返回 304 状态码

同源策略相关 Header

字段名类型说明
Access-Control-Allow-Originstring告知客户端可以访问的源,如:*
Access-Control-Allow-Methodsstring告知客户端可以访问的方法,如:GET, POST, PUT, DELETE
Access-Control-Allow-Headersstring告知客户端可以发送的请求头,如果有自定义 header,则需要在这里声明
Access-Control-Expose-Headersstring告知浏览器可以访问的响应头,默认情况下,只有 6 个基本字段可以被浏览器访问:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
Access-Control-Max-Ageinteger指定预检请求的结果可以缓存多久(以秒为单位)。
Access-Control-Allow-Credentialsstring告知客户端是否可以发送 cookie,如:true

对于 POST、PUT、DELETE 等“高危”方法或者带有自定义请求头的方法,通常需要发送一个预检请求(OPTIONS)进行检查。

响应码规范

必须使用正确的 HTTP 状态码。HTTP 协议定义的状态码分类如下:

状态码分类说明
1xx信息性状态码表示临时响应,需要客户端进一步操作
2xx成功状态码表示请求成功
3xx重定向状态码表示需要客户端进一步操作
4xx客户端错误状态码表示客户端请求错误,比如 400 错误请求,401 未认证,403 禁止访问,404 未找到资源,405 方法不允许,429 请求过多
5xx服务器错误状态码表示服务器处理请求错误,比如 500 服务器错误,502 网关错误,503 服务不可用,504 网关超时
  • 在 API 设计开发时,至少需要区分 2xx、 4xx、5xx 三种状态码。
  • 在必要时可以细化状态码
    • 创建成功:201 Created
    • 查询成功:200 OK
    • 更新成功:200 OK,或 204 No Content,表示执行成功但不返回数据
    • 删除成功:200 OK;未找到资源:404 Not Found,资源已被删除或不可用 410
响应体规范
  • 对于 List 操作,返回的是资源数组;如果没有资源,则返回空数组。
  • 对于 GET/POST/PUT,通常返回资源详情对象
  • 对于失败的请求,除了 HTTP 状态码外,需要有更详细的错误信息。下面是常用字段:
字段名类型是否必填说明
codestring业务自定义的错误码
messagestring用户能读懂的出错信息
targetstring出错目标对象
detailsError[]错误列表
helpstring帮助文档地址

需要注意不要在 details 中异常调用栈信息,这个应该在服务日志中打印。

向后兼容规范

1. 不能减少现有参数

API 的修改或升级,必须是做加法,不能是减法。

2. 新增参数或请求数据必须有默认值

新增参数时,必须有默认值,不能是必选参数。否则会导致现有的客户端调用失败。

3. 不能修改原 API 的语义和签名

已经发布的 API 有用户在使用,因此任何对 API 的改动都不能对使用方造成负面影响。为此必须做到:

  • 新增的查询参数不能是必选的。
  • HTTP 头和状态码不能修改,可以增加,但必须有默认值。
  • 请求数据中,必选参数不能有任何修改,包括参数名、类型、值范围(可以扩大,但不能缩小)。
  • 响应数据中,必选参数不能有任何修改,包括参数名、类型、值范围(可以扩大,但不能缩小)。

如果做不到兼容,则需要升级 API 版本。

文档规范

API 必须有文档说明,最佳实践是使用 Swagger 生成 API 文档。内部应该有统一的 API 文档管理平台,对外提供 API 文档的访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/39579.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python机器学习】3.5. 决策树实战:基于Iris数据集

喜欢的话别忘了点赞、收藏加关注哦&#xff08;关注即可查看全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 本文紧承 3.1. 决策树理论(基础) 和 3.2. 决策树理论(进阶)&#xff0c;没看过的建议先看理论分…

Unity2022发布Webgl2微信小游戏部分真机黑屏

复现规律&#xff1a; Unity PlayerSetting中取消勾选ShowSplashScreen 分析&#xff1a; 在Unity中&#xff0c;Splash Screen&#xff08;启动画面&#xff09; 不仅是视觉上的加载动画&#xff0c;还承担了关键的引擎初始化、资源预加载和渲染环境准备等底层逻辑。禁用后导…

docker desktop 集成WSL Ubuntu22.04

Windows docker desktop 设置WSL ubuntu 22.04启用与其他发行版的集成 Windows docker desktop 安装参考 wsl ubuntu 22.04 查看我宿主机的docker desktop 容器全部的信息 wsl -d Ubuntu-22.04 -u root

快速入手-基于Django的主子表间操作mysql(五)

1、如果该表中存在外键&#xff0c;结合实际业务情况&#xff0c;那可以这么写&#xff1a; 2、针对特殊的字典类型&#xff0c;可以这么定义 3、获取元组中的字典值和子表中的value值方法 4、对应的前端页面写法

使用cursor开发java案例——springboot整合elasticsearch

安装elasticsearch 打开cursor&#xff0c;输入如下提示词 使用springboot整合elasticsearch。其中elasticsearch服务器ip&#xff1a;192.168.236.134 管理员用户名elastic 管理员密码 PdQy_xfR2yLhpok*MK_ 监听端口9200点Accept all 使用idea打开生成的项目 &#xff0…

Deepseek结合企业数据挖掘平台能够给企业提升哪些效益?

Deepseek&#xff08;深度求索&#xff09;作为智能系统&#xff0c;在政务办公领域可通过AI技术优化流程、提升效率&#xff0c;具体应用场景分析如下&#xff1a; 1. 智能公文处理与流转 自动分类与审核 利用NLP解析公文内容&#xff0c;自动分类&#xff08;如请示、报告、通…

vite中sass警告JS API过期

在Vite创建项目中引入Sass弹出The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 vite中sass警告JS API过期 The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0 警告提示表明你当前正在使用的 Dart Sass 版本中&#xff0c;旧的…

jenkins+1panel面板java运行环境自动化部署java项目

本文章不包含1panel面板安装、jenkins部署、jenkins连接git服务器等操作教程&#xff0c;如有需要可以抽空后期补上 jenkins安装插件Publish Over SSH 在系统配置添加服务器 查看项目的工作空间 项目Configure->构Post Steps选择Send files or execute commands over SSH…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能📚页面效果📚指令输入�…

SpringBoot与Redisson整合,用注解方式解决分布式锁的使用问题

文章引用&#xff1a;https://mp.weixin.qq.com/s/XgdKE2rBKL0-nFk2NJPuyg 一、单个服务 1.代码 该接口的作用是累加一个值&#xff0c;访问一次该值加1 RestController public class LockController {Autowiredprivate StringRedisTemplate stringRedisTemplate;GetMappin…

SpringBoot 统一功能处理

目录 1. 拦截器 1.1 什么是拦截器 1.2 定义拦截器 1.3 注册拦截器 1.3.1 拦截路径 1.4 登录校验 - 拦截器 1.4.1 定义拦截器 1.4.2 注册拦截器 1.4.3 前端代码 1.5 DisPatchServlet 底层源码解析 2. 统一结果返回格式 2.1 ResponseBodyAdvice 2.1.1 存在问题1 - 原本…

电机控制常见面试问题(十八)

文章目录 一.电机控制高级拓扑结构1.LLC 二.谈谈电压器饱和后果三.电压器绕组连接方式的影响四.有源逆变的条件 一.电机控制高级拓扑结构 1.LLC LLC是什么&#xff1f;—— 一个会"变魔术"的电源盒子 想象你有一个魔法盒子&#xff0c;能把电池的电压变大或变小&…

如何解决用户名文件夹是中文导致的识别不到路径,获取不到ssh密匙

如果你不想更改你的文件夹用户名导致之前配置的环境变量及相关软件失效&#xff0c;那么只需要指定自定义路径生成密钥 完整解决方案 1. 设置一个简单的 HOME 路径 由于你的用户名包含中文字符&#xff0c;导致默认路径 无法正确解析。我们可以通过修改 HOME 环境变量&#…

Python入门基础

python基础类型转换 str()与int()类型转换 name 张三 age 20 print(type(name),type(age))print(我叫name 今年&#xff0c; str(age)岁 )a10 b198.8 cFalse print(type(a),type(b),type(c)) print(str(a),str(b),str(c))s1 128 f198.7 s276.77 ffTrue s3hello print(type(s…

GithubPages+自定义域名+Cloudfare加速+浏览器收录(2025最新排坑)

前言 最近刷到一个小视频&#xff0c;讲述了选择域名选择的三宗罪&#xff0c;分别是 不要使用 .net&#xff0c;因为它价格贵&#xff0c;但是在顶级域名中的 SEO 效果却不是很好&#xff0c;也就是性价比很低不要使用 .cn&#xff0c;因为国外访问该网站可能会很慢&#xf…

监控IP,网站将异常情况通过飞书机器人发至指定群内

界面如下&#xff0c;丑是丑了点&#xff0c;但主打一个实用。 主要就是通过ping&#xff0c;就是一直在ping&#xff0c;当不通的时候&#xff0c;就根据你设置的报警时间&#xff0c;主要是利用飞书机器人来给飞书指定群里发异常信息报警。 直接上代码 import subprocess i…

2018扬州大学876农业机械学概论填空名词解释简答

2018 7.全喂入式脱粒机根据脱粒装置的工作特点&#xff0c;主要通过脱粒部件的结构与作用方式区分。其中&#xff0c;纹杆式脱粒装置依靠纹杆的击打、搓擦作用脱粒&#xff1b;弓齿式脱粒装置则通过弓齿的梳刷、打击实现脱粒。 8.主犁体作为犁具核心部件&#xff0c;各部分分…

C++KNN 算法应用痛点:从受噪声干扰到精准预测的突破

在机器学习算法家族中,K近邻(K-Nearest Neighbors,KNN)算法以其概念简单却又异常强大的特性脱颖而出。作为一名长期从事高性能计算优化的C++专家,我始终对KNN算法情有独钟。为何如此?想象一下,在数十种复杂的算法中,有一种算法能够不需要繁琐的数学推导,仅凭直觉就能理…

996引擎-接口测试:消息Tips

996引擎-接口测试:消息Tips 发送视野内广播消息 sendrefluamsg发送聊天框消息 sendmsg发送地图消息 sendmapmsg打印消息到控制台 release_print发送自定义颜色的文字信息 guildnoticemsg测试NPC参考资料发送视野内广播消息 sendrefluamsg function npc_test_onclick1(player)-…

2025年上软考——【系统架构设计师】考前60天冲刺学习指南!!!

距离2025上半年“系统架构设计师”考试已经只剩两个月了&#xff0c;还没有开始备考的小伙伴赶紧行动起来。为了帮助大家更好的冲刺学习&#xff0c;特此提供一份考前60天学习指南。本指南包括考情分析、学习规划、冲刺攻略三个部分&#xff0c;可以参考此指南进行最后的复习要…