Tips
Go
(18条消息) Go语言自学系列 | golang包_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之channel的遍历_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之select switch_COCOgsta的博客-CSDN博客_golang select switch
(18条消息) Go语言自学系列 | golang并发编程之runtime包_COCOgsta的博客-CSDN博客_golang runtime包
(18条消息) Go语言自学系列 | golang接口值类型接收者和指针类型接收者_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之Timer_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang方法_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之WaitGroup实现同步_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang构造函数_COCOgsta的博客-CSDN博客_golang 构造函数
(18条消息) Go语言自学系列 | golang方法接收者类型_COCOgsta的博客-CSDN博客_golang 方法接收者
(18条消息) Go语言自学系列 | golang接口_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang接口和类型的关系_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang结构体_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang结构体_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang标准库os模块 - File文件读操作_COCOgsta的博客-CSDN博客_golang os.file
(18条消息) Go语言自学系列 | golang继承_COCOgsta的博客-CSDN博客_golang 继承
(18条消息) Go语言自学系列 | golang嵌套结构体_COCOgsta的博客-CSDN博客_golang 结构体嵌套
(18条消息) Go语言自学系列 | golang并发编程之Mutex互斥锁实现同步_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发变成之通道channel_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang并发编程之原子操作详解_COCOgsta的博客-CSDN博客_golang 原子操作
(18条消息) Go语言自学系列 | golang并发编程之原子变量的引入_COCOgsta的博客-CSDN博客_go 原子变量
(18条消息) Go语言自学系列 | golang并发编程之协程_COCOgsta的博客-CSDN博客_golang 协程 并发
(18条消息) Go语言自学系列 | golang接口嵌套_COCOgsta的博客-CSDN博客_golang 接口嵌套
(18条消息) Go语言自学系列 | golang包管理工具go module_COCOgsta的博客-CSDN博客_golang 包管理器
(18条消息) Go语言自学系列 | golang标准库os模块 - File文件写操作_COCOgsta的博客-CSDN博客_go os模块
(18条消息) Go语言自学系列 | golang结构体的初始化_COCOgsta的博客-CSDN博客_golang 结构体初始化
(18条消息) Go语言自学系列 | golang通过接口实现OCP设计原则_COCOgsta的博客-CSDN博客
(18条消息) Go语言自学系列 | golang标准库os包进程相关操作_COCOgsta的博客-CSDN博客_golang os包
(18条消息) Go语言自学系列 | golang标准库ioutil包_COCOgsta的博客-CSDN博客_golang ioutil
(18条消息) Go语言自学系列 | golang标准库os模块 - 文件目录相关_COCOgsta的博客-CSDN博客_go语言os库
Golang技术栈,Golang文章、教程、视频分享!
(18条消息) Go语言自学系列 | golang结构体指针_COCOgsta的博客-CSDN博客_golang 结构体指针
Ansible
太厉害了,终于有人能把Ansible讲的明明白白了,建议收藏_互联网老辛
ansible.cfg配置详解
Docker
Docker部署
linux安装docker和Docker Compose
linux 安装 docker
Docker中安装Docker遇到的问题处理
Docker常用命令
docker常用命令小结
docker 彻底卸载
Docker pull 时报错:Get https://registry-1.docker.io/v2/library/mysql: net/http: TLS handshake timeout
Docker 拉镜像无法访问 registry-x.docker.io 问题(Centos7)
docker 容器内没有权限
Linux中关闭selinux的方法是什么?
docker run 生成 docker-compose
Docker覆盖网络部署
docker pull后台拉取镜像
docker hub
Redis
Redis 集群别乱搭,这才是正确的姿势
linux_离线_redis安装
怎么实现Redis的高可用?(主从、哨兵、集群) - 雨点的名字 - 博客园
redis集群离线安装
always-show-logo yes
Redis集群搭建及原理
[ERR] Node 172.168.63.202:7001 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or contains some - 亲爱的不二999 - 博客园
Redis daemonize介绍
redis 下载地址
Redis的redis.conf配置注释详解(三) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(一) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(二) - 云+社区 - 腾讯云
Redis的redis.conf配置注释详解(四) - 云+社区 - 腾讯云
Linux
在终端连接ssh的断开关闭退出的方法
漏洞扫描 - 灰信网(软件开发博客聚合)
find 命令的参数详解
vim 编辑器搜索功能
非root安装rpm时,mockbuild does not exist
Using a SSH password instead of a key is not possible because Host Key checking
(9条消息) 安全扫描5353端口mDNS服务漏洞问题_NamiJava的博客-CSDN博客_5353端口
Linux中使用rpm命令安装rpm包
ssh-copy-id非22端口的使用方法
How To Resolve SSH Weak Key Exchange Algorithms on CentOS7 or RHEL7 - infotechys.com
Linux cp 命令
yum 下载全量依赖 rpm 包及离线安装(终极解决方案) - 叨叨软件测试 - 博客园
How To Resolve SSH Weak Key Exchange Algorithms on CentOS7 or RHEL7 - infotechys.com
RPM zlib 下载地址
运维架构网站
欢迎来到 Jinja2
/usr/local/bin/ss-server -uv -c /etc/shadowsocks-libev/config.json -f /var/run/s
ruby 安装Openssl 默认安装位置
Linux 常用命令学习 | 菜鸟教程
linux 重命名文件和文件夹
linux命令快速指南
ipvsadm
Linux 下查找日志中的关键字
Linux 切割大 log 日志
CentOS7 关于网络的设置
rsync 命令_Linux rsync 命令用法详解:远程数据同步工具
linux 可视化界面安装
[问题已处理]-执行yum卡住无响应
GCC/G++升级高版本
ELK
Docker部署ELK
ELK+kafka+filebeat+Prometheus+Grafana - SegmentFault 思否
(9条消息) Elasticsearch设置账号密码_huas_xq的博客-CSDN博客_elasticsearch设置密码
Elasticsearch 7.X 性能优化
Elasticsearch-滚动更新
Elasticsearch 的内存优化_大数据系统
Elasticsearch之yml配置文件
ES 索引为Yellow状态
Logstash:Grok filter 入门
logstash grok 多项匹配
Mysql
Mysql相关Tip
基于ShardingJDBC实现数据库读写分离 - 墨天轮
MySQL-MHA高可用方案
京东三面:我要查询千万级数据量的表,怎么操作?
OpenStack
(16条消息) openstack项目中遇到的各种问题总结 其二(云主机迁移、ceph及扩展分区)_weixin_34104341的博客-CSDN博客
OpenStack组件介绍
百度大佬OpenStack流程
openstack各组件介绍
OpenStack生产实际问题总结(一)
OpenStack Train版离线部署
使用Packstack搭建OpenStack
K8S
K8S部署
K8S 集群部署
kubeadm 重新 init 和 join-pudn.com
Kubernetes 实战总结 - 阿里云 ECS 自建 K8S 集群 Kubernetes 实战总结 - 自定义 Prometheus
【K8S实战系列-清理篇1】k8s docker 删除没用的资源
Flannel Pod Bug汇总
Java
Jdk 部署
JDK部署
java线程池ThreadPoolExecutor类使用详解 - bigfan - 博客园
ShardingJDBC实现多数据库节点分库分表 - 墨天轮
Maven Repository: Search/Browse/Explore
其他
Git在阿里,我们如何管理代码分支?
chrome F12调试网页出现Paused in debugger
体验IntelliJ IDEA的远程开发(Remote Development) - 掘金
Idea远程调试
PDF转MD
强哥分享干货
优秀开源项目集合
vercel 配合Github 搭建项目Doc门户
如何用 Github Issues 写技术博客?
Idea 2021.3 Maven 3.8.1 报错 Blocked mirror for repositories 解决
列出maven依赖
[2022-09 持续更新] 谷歌 google 镜像 / Sci-Hub 可用网址 / Github 镜像可用网址总结
阿里云ECS迁移
linux访问github
一文教你使用 Docker 启动并安装 Nacos-腾讯云开发者社区-腾讯云
Nginx
Nginx 部署
Nginx 部署安装
Nginx反向代理cookie丢失的问题_longzhoufeng的博客-CSDN博客_nginx 代理后cookie丢失
Linux 系统 Https 证书生成与Nginx配置 https
数据仓库
实时数仓
松果出行 x StarRocks:实时数仓新范式的实践之路
实时数据仓库的一些分层和分层需要处理的事情,以及数据流向
湖仓一体电商项目
湖仓一体电商项目(一):项目背景和架构介绍
湖仓一体电商项目(二):项目使用技术及版本和基础环境准备
湖仓一体电商项目(三):3万字带你从头开始搭建12个大数据项目基础组件
数仓笔记
数仓学习总结
数仓常用平台和框架
数仓学习笔记
数仓技术选型
尚硅谷教程
尚硅谷学习笔记
尚硅谷所有已知的课件资料
尚硅谷大数据项目之尚品汇(11数据质量管理V4.0)
尚硅谷大数据项目之尚品汇(10元数据管理AtlasV4.0)
尚硅谷大数据项目之尚品汇(9权限管理RangerV4.0)
尚硅谷大数据项目之尚品汇(8安全环境实战V4.0)
尚硅谷大数据项目之尚品汇(7用户认证KerberosV4.1)
尚硅谷大数据项目之尚品汇(6集群监控ZabbixV4.1)
尚硅谷大数据项目之尚品汇(5即席查询PrestoKylinV4.0)
尚硅谷大数据项目之尚品汇(4可视化报表SupersetV4.0)
尚硅谷大数据项目之尚品汇(3数据仓库系统)V4.2.0
尚硅谷大数据项目之尚品汇(2业务数据采集平台)V4.1.0
尚硅谷大数据项目之尚品汇(1用户行为采集平台)V4.1.0
数仓治理
数据中台 元数据规范
数据中台的那些 “经验与陷阱”
2万字详解数据仓库数据指标数据治理体系建设方法论
数据仓库,为什么需要分层建设和管理? | 人人都是产品经理
网易数帆数据治理演进
数仓技术
一文看懂大数据生态圈完整知识体系
阿里云—升舱 - 数据仓库升级白皮书
最全企业级数仓建设迭代版(4W字建议收藏)
基于Hue,Dolphinscheduler,HIVE分析数据仓库层级实现及项目需求案例实践分析
详解数据仓库分层架构
数据仓库技术细节
大数据平台组件介绍
总览 2016-2021 年全球机器学习、人工智能和大数据行业技术地图
Apache DolphinScheduler 3.0.0 正式版发布!
数据仓库面试题——介绍下数据仓库
数据仓库为什么要分层,各层的作用是什么
Databend v0.8 发布,基于 Rust 开发的现代化云数据仓库 - OSCHINA - 中文开源技术交流社区
数据中台
数据中台设计
大数据同步工具之 FlinkCDC/Canal/Debezium 对比
有数数据开发平台文档
Shell
Linux Shell 命令参数
shell 脚本编程
一篇教会你写 90% 的 Shell 脚本
Kibana
Kibana 查询语言(KQL)
Kibana:在 Kibana 中的四种表格制作方式
Kafka
Kafka部署
canal 动态监控 Mysql,将 binlog 日志解析后,把采集到的数据发送到 Kafka
OpenApi
OpenAPI 标准规范,了解一下?
OpenApi学术论文
贵阳市政府数据开放平台设计与实现
OpenAPI简介
开放平台:运营模式与技术架构研究综述
管理
技术部门Leader是不是一定要技术大牛担任?
华为管理体系流程介绍
DevOps
*Ops
XOps 已经成为一个流行的术语 - 它是什么?
Practical Linux DevOps
Jenkins 2.x实践指南 (翟志军)
Jenkins 2权威指南 ((美)布伦特·莱斯特(Brent Laster)
DevOps组件高可用的思路
KeepAlived
VIP + KEEPALIVED + LVS 遇到Connection Peer的问题的解决
MinIO
MinIO部署
Minio 分布式集群搭建部署
Minio 入门系列【16】Minio 分片上传文件 putObject 接口流程源码分析
MinioAPI 浅入及问题
部署 minio 兼容 aws S3 模式
超详细分布式对象存储 MinIO 实战教程
Hadoop
Hadoop 部署
Hadoop集群部署
windows 搭建 hadoop 环境(解决 HADOOP_HOME and hadoop.home.dir are unset
Hadoop 集群搭建和简单应用(参考下文)
Hadoop 启动 NameNode 报错 ERROR: Cannot set priority of namenode process 2639
jps 命令查看 DataNode 进程不见了 (hadoop3.0 亲测可用)
hadoop 报错: Operation category READ is not supported in state standby
Spark
Spark 部署
Spark 集群部署
spark 心跳超时分析 Cannot receive any reply in 120 seconds
Spark学习笔记
apache spark - Failed to find data source: parquet, when building with sbt assembly
Spark Thrift Server 架构和原理介绍
InLong
InLong 部署
Apache InLong部署文档
安装部署 - Docker 部署 - 《Apache InLong v1.2 中文文档》 - 书栈网 · BookStack
基于 Apache Flink SQL 的 InLong Sort ETL 方案解析
关于 Apache Pulsar 在 Apache InLong 接入数据
zookeeper
zookeeper 部署
使用 Docker 搭建 Zookeeper 集群
美团技术团队
StarRocks
StarRocks技术白皮书(在线版)
JuiceFS
AI 场景存储优化:云知声超算平台基于 JuiceFS 的存储实践
JuiceFS 在 Elasticsearch/ClickHouse 温冷数据存储中的实践
JuiceFS format
元数据备份和恢复 | JuiceFS Document Center
JuiceFS 元数据引擎选型指南
Apache Hudi 使用文件聚类功能 (Clustering) 解决小文件过多的问题
普罗米修斯
k8s 之 Prometheus(普罗米修斯)监控,简单梳理下 K8S 监控流程
k8s 部署 - 使用helm3部署监控prometheus(普罗米修斯),从零到有,一文搞定
k8s 部署 - 使用 helm3 部署监控 prometheus(普罗米修斯),从零到有,一文搞定
k8s 部署 - 如何完善 k8s 中 Prometheus(普罗米修斯)监控项目呢?
k8s 部署 - k8s 中 Prometheus(普罗米修斯)的大屏展示 Grafana + 监控报警
zabbix
一文带你掌握 Zabbix 监控系统
Stream Collectors
Nvidia
Nvidia API
CUDA Nvidia驱动安装
NVIDIA驱动失效简单解决方案:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver.
ubuntu 20 CUDA12.1安装流程
nvidia开启持久化模式
nvidia-smi 开启持久化
Harbor
Harbor部署文档
Docker 爆出 it doesn't contain any IP SANs
pandoc
其他知识
大模型
COS 597G (Fall 2022): Understanding Large Language Models
如何优雅的使用各类LLM
ChatGLM3在线搜索功能升级
当ChatGLM3能用搜索引擎时
OCR神器,PDF、数学公式都能转
Stable Diffusion 动画animatediff-cli-prompt-travel
基于ERNIE Bot自定义虚拟数字人生成
pika负面提示词
开通GPT4的方式
GPT4网站
低价开通GPT Plus
大模型应用场景分享
AppAgent AutoGPT变体
机器学习
最大似然估计
权衡偏差(Bias)和方差(Variance)以最小化均方误差(Mean Squared Error, MSE)
伯努利分布
方差计算公式
均值的高斯分布估计
没有免费午餐定理
贝叶斯误差
非参数模型
最近邻回归
表示容量
最优容量
权重衰减
正则化项
Sora
Sora官方提示词
看完32篇论文,你大概就知道Sora如何炼成? |【经纬低调出品】
Sora论文
Sora 物理悖谬的几何解释
Sora 技术栈讨论
RAG垂直落地
DB-GPT与TeleChat-7B搭建相关RAG知识库
ChatWithRTX
ChatRTX安装教程
ChatWithRTX 踩坑记录
ChatWithRTX 使用其他量化模型
ChatWithRTX介绍
RAG 相关资料
英伟达—大模型结合 RAG 构建客服场景自动问答
又一大模型技术开源!有道自研RAG引擎QAnything正式开放下载
收藏!RAG入门参考资料开源大总结:RAG综述、介绍、比较、预处理、RAG Embedding等
RAG调研
解决现代RAG实际生产问题
解决现代 RAG 系统中的生产问题-II
Modular RAG and RAG Flow: Part Ⅰ
Modular RAG and RAG Flow: Part II
先进的Retriever技术来增强你的RAGs
高级RAG — 使用假设文档嵌入 (HyDE) 改进检索
提升 RAG:选择最佳嵌入和 Reranker 模型
LangGraph
增强型RAG:re-rank
LightRAG:使用 PyTorch 为 LLM 应用程序提供支持
模型训练
GPU相关资料
[教程] conda安装简明教程(基于miniconda和Windows)
PyTorch CUDA对应版本 | PyTorch
资料
李一舟课程全集
零碎资料
苹果各服共享ID
数据中心网络技术概览
华为大模型训练学习笔记
百度AIGC工程师认证考试答案(可换取工信部证书)
百度智能云生成式AI认证工程师 考试和证书查询指南
深入理解 Megatron-LM(1)基础知识
QAnything
接入QAnything的AI问答知识库,可私有化部署的企业级WIKI知识库
wsl --update失效Error code: Wsl/UpdatePackage/0x80240438的解决办法
Docker Desktop 启动docker engine一直转圈解决方法
win10开启了hyper-v,docker 启动还是报错 docker desktop windows hypervisor is not present
WSL虚拟磁盘过大,ext4迁移 Windows 中创建软链接和硬链接
WSL2切换默认的Linux子系统
Windows的WSL子系统,自动开启sshd服务
新版docker desktop设置wsl(使用windown的子系统)
WSL 开启ssh
Windows安装网易开源QAnything打造智能客服系统
芯片
国内互联网大厂自研芯片梳理
超算平台—算力供应商
Linux 磁盘扩容
Linux使用growpart工具进行磁盘热扩容(非LVM扩容方式)
关于centos7 扩容提示no tools available to resize disk with 'gpt' - o夜雨随风o - 博客园
(小插曲)neo4j配置apoc插件后检查版本发现:Unknown function ‘apoc.version‘ “EXPLAIN RETURN apoc.version()“
vfio-pci与igb_uio映射硬件资源到DPDK的流程分析
KubeVirt
vnc server配置、启动、重启与连接 - 王约翰 - 博客园
虚拟机Bug解决方案
kubevirt 如何通过CDI上传镜像文件
在 K8S 上也能跑 VM!KubeVirt 簡介與建立(部署篇) | Cloud Solutions
KubeVirt 04:容器化数据导入 – 小菜园
Python
安装 flash_attn
手把手教你在linux上安装pytorch与cuda
AI
在启智社区基于PyTorch运行国产算力卡的模型训练实验
Scaling law
免费的GPT3.5 API
AI Engineer Roadmap & Resources 🤖
模型排行
edk2
K8S删除Evicted状态的pod
docker 中启动 docker
远程本地多用户桌面1.17(一种不让电脑跟你抢键鼠的思路) - 哔哩哔哩
华为鲲鹏服务器(ARM架构)部署Prometheus
在Linux上安装配置Grafana_AI开发平台ModelArts_华为云
-
+
首页
OpenAPI 标准规范,了解一下?
> 本文由 [简悦 SimpRead](http://ksria.com/simpread/) 转码, 原文地址 [www.tuicool.com](https://www.tuicool.com/articles/my2Qrmr) 摘要: 原创出处 朱小厮的博客 「朱小厮」欢迎转载,保留摘要,谢谢! * [什么是 API 规范](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [OpenAPI 规范](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [一、协议](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [二、版本(Version)](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [三、Schema](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [四、以资源为中心的 URL 设计](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [五、正确使用 HTTP Method](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [六、状态码 (Status Code)](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [七、错误处理(Error Handling)](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [八、命名规则](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [九、认证和授权(Authentication & Authorization)](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [十、限流(RateLimit)](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) * [十一、编写优秀的文档](https://www.iocoder.cn/Fight/OpenAPI-standards-understand/) ![](https://img0.tuicool.com/rmiYV3N.jpg!web) 关注 **微信公众号:【芋道源码】** 有福利: 1. RocketMQ / MyCAT / Sharding-JDBC **所有** 源码分析文章列表 2. RocketMQ / MyCAT / Sharding-JDBC **中文注释源码 GitHub 地址** 3. 您对于源码的疑问每条留言 **都** 将得到 **认真** 回复。 **甚至不知道如何读源码也可以请教噢** 。 4. **新的** 源码解析文章 **实时** 收到通知。 **每周更新一篇左右** 。 5. **认真的** 源码交流微信群。 什么是 API 规范 ---------- API 是模块或者子系统之间交互的接口定义。好的系统架构离不开好的 API 设计,而一个设计不够完善的 API 则注定会导致系统的后续发展和维护非常困难。在关键环节制定明确的 API 规范有助于 Service 对内提高产品间互通的效率,对外提供一致的使用体验,也有助于更好地被集成。 对于 API 规范,比较知名的是 **OpenAPI Specfication** 和 **Google API Design Guide** 。前者针对 RESTful API 设计在细节层面给出了非常具体的规定,已经成为 RESTful API 设计领域的事实标准,而后者则主要从云厂商的角度提出许多最佳实践性质的规范与建议,这些原则不仅仅适用于 RESTful API,也适合其他类型 API 设计。 虽然 RESTful 设计风格曝光率很高,但并不是所有云服务商都选择了完全遵循 RESTful,例如 AWS 和 **阿里云** RPC 风格反而占了大多数,Google 和 Azure 则 RESTful 居多。 RESTful API 的优势是 HTTP 具备更好的易用性,让异构系统更容易集成,且开发执行效率比较高,面向资源要求也比较高。而 RPC API 可以使用更广泛的框架和方案,技术层面更底层也更为灵活,设计起来相对简单,掌握起来有一定门槛,架构上更加复杂。RESTful 与 RPC 模式对比如下: <table><thead><tr><th width="36%"></th><th width="34%">RESTful API</th><th width="30%">RPC API</th></tr></thead><tbody><tr><td>是否有统一规范</td><td>HTTP</td><td>无</td></tr><tr><td>面向资源</td><td>是</td><td>不确定</td></tr><tr><td>性能</td><td>中</td><td>高</td></tr><tr><td>通用性</td><td>高</td><td>弱</td></tr><tr><td>复杂度</td><td>中</td><td>高</td></tr></tbody></table> 如果强制统一风格,有些适合 RESTful 风格的服务非要使用 RPC 的话,看起来就会比较丑陋,如果只是一个过程化的服务调用,往 RESTful 资源化设计方向去靠会比较困难。但如果不强制使用统一风格,会造成针对 API 的体系化支持会更加复杂,例如为兼容两种风格 SDK 的自动化支持需要两套代码。 选择 API 风格时要考虑几个问题: * 选择支持哪种风格,才能更好地体现业务特性,让客户操作起来更加方便; * 设计 API 时能否面向资源设计,相应的工程人员是否具备做这种设计的能力; * 针对这种风格工具链的支持是否到位,投入产出比如何; * 业界流行的趋势如何,是否需要考虑与其他系统体系的互操作。 用户使用 API 来访问 Service,本质上是想通过对某种资源执行特定的操作来完成一个业务动作。对于资源有两个关键点:一是要有统一的资源模型;二是要明确资源关系。统一的资源模型对 Service 的帮助是巨大的: * 它可以使 API 具有更清晰的结构,帮助用户理解; * 它可以帮助对比 API 与后台实体关系模型,更容易提供更完整的 API 服务; * 它可以使产品协作更加顺畅,对资源的操作也更加规范化; * 它可以使云服务底层平台实现起来更统一、更方便; * 它可以使围绕 API 的生态集成起来更加简单、高效。 确定了设计模式和资源模型后,就需要考虑 API 的设计细节了,诸如 API 名称、参数名、属性名称、数据格式、错误码之类的信息。除此之外,还要考虑以下一些问题: * 在 API 命名的时候,遵循什么样的范式来确保大体风格相似?动词、名词、介词如何组合才能保持 API 风格看起来比较统一,降低理解成本? * 对于类似的操作,有没有使用规范?有哪些公共的标准词汇使得同类型的操作可以比较容易理解,避免使用晦涩奇怪的词汇(例如读操作,Read/Query/Describe/List/Get 中都在什么场合使用什么动词)? * 被广泛使用的参数如何尽可能保持一致,避免不同产品的表达混乱的情况(例如分页参数用 PageNumber 还是 PageNum)? * 对于常用的场景,例如幂等、分页、异步 API 的设计有没有统一的规范,避免使用体验不一致? * 错误码应该怎么设计?公共错误码怎么统一,业务错误码怎么表达? 上述问题都是实际研发过程中要注意的,要全部罗列的话远不止这些。API 的用词描述是 Service 展现给外部用户的第一印象,绝非随意写就。对人员有一定规模,内部有多条产品线的组织来说,如何协调组织的各个部分对外具有统一的体验是个很大挑战。 Service 在管理 API 时应该考虑一些具体的规范,对命名规则、标准词汇、最佳实践模式、错误码等信息都有明确的规定,同时用系统化、平台化的手段来管理 API,确保不走偏。设计风格不是云服务 API 设计中致命的问题,但是它关乎云服务外表形象,不可不察。 API 是后端服务的外部表达,是服务就有可能出现问题,无论这个问题是可预期的还是不可预期的。如果只考虑功能本身功能特性,而忽视对异常情况的设计,当问题出现的时候业务本身可能无法感知造成服务异常,更重要的是站在客户角度去看,不能有效获取错误原因是非常痛苦的,很多时候只能束手无策,降低云服务提供商的整体口碑,甚至损害营收。 OpenAPI 规范 ---------- 本规范基于 RESTful 风格的架构设计准则,广泛参考 GitHub、Azure、Google API Design Guide、腾讯云、阿里云等公开资料,兼顾现有实际情况和未来发展做一个概括性记录总结。 一、协议 ---- API 与用户的通信协议,总是使用 HTTPS 协议。这个和 RESTful API 本身没有很大的关系,但是对于增加网站的安全是非常重要的。特别如果你提供的是公开 API,用户的信息泄露或者被攻击会严重影响网站的信誉。 二、版本(Version) ------------- 关于版本的设计有 3 种形式: 1. 将 API 的版本号放入 URL 中,如: `http://api.example.com/v1` ,这样方便和直观; 2. 将版本号记录在 url query 中,如: `http://api.example.com?param1=val&version=1.0` 中的 version 参数。 3. 将版本号放在 HTTP 头信息中,基于的准则是:不同的版本,可以理解成同一种资源的不同形式,所以应该采用同一个 URL。如: `Accept: application/json; version=1.0` ,可以参考 **Github API Design** 和 **Versioning REST Services** ; 根据现有的实际情况,如果是为了兼容已存在的服务接口,可以采用对应的形式。如果是新构建的体系结构,建议采用第三种。 三、Schema -------- URI 的格式定义如下: `URI = scheme "://" authority "/" path \[ "?" query \] \[ "#" fragment \]` URL 是 URI 的一个子集 (一种具体实现),对于 REST API 来说一个资源一般对应一个唯一的 URI(URL)。在 URL 的设计中,我们会遵循一些规则,使接口看起透明易读,方便使用者调用。 “/“分隔符一般用来对资源层级的划分。对于 RESTful API 来说,”/“只是一个分隔符,并无其他含义。为了避免混淆,”/“不应该出现在 URL 的末尾。 URL 中尽量使用连字符”-“代替下划线”_” 的使用。连字符”-“一般用来分割 URL 中出现的字符串 (单词),来提高 URL 的可读性,例如: `http://api.example.restapi.org/blogs/mark-masse/entries/this-is-my-first-post` 。使用下划线” _“来分割字符串 (单词) 可能会和链接的样式冲突重叠,而影响阅读性。但实际上,”-“和”_ “对 URL 中字符串的分割语意上还是有些差异的:”-“分割的字符串 (单词) 一般各自都具有独立的含义,可参见上面的例子。而”_”一般用于对一个整体含义的字符串做了层级的分割,方便阅读,例如你想在 URL 中体现一个 IP 地址的信息:210_110_25_88 . (欢迎关注:朱小厮的博客) #### URL 应该统一使用小写字母。 URL 中不要包含文件 (脚本) 的扩展名。例如 `.json` 之内的就不要出现了,对于接口来说没有任何实际的意义。如果是想对返回的数据内容格式标示的话,通过 HTTP Header 中的 Content-Type 字段更好一些。 对于响应返回的格式,JSON 因为它的可读性、紧凑性以及多种语言支持等优点,成为了 HTTP API 最常用的返回格式。因此,最好采用 JSON 作为返回内容的格式。如果用户需要其他格式,比如 `xml` ,应该在请求头部 `Accept` 中指定。对于不支持的格式,服务端需要返回正确的 `status code` ,并给出详细的说明。 #### JSON 中的所有字段都应该用小写的蛇形命名形式,而不是采用驼峰命名。 四、以资源为中心的 URL 设计 ---------------- 资源是 `Restful API` 的核心元素,所有的操作都是针对特定资源进行的。而资源就是 `URL` (Uniform Resoure Locator)表示的,所以简洁、清晰、结构化的 URL 设计是至关重要的。Github 可以说是这方面的典范,下面我们就拿 `repository` 来说明: ``` /users/:username/repos /users/:org/repos /repos/:owner/:repo /repos/:owner/:repo/tags /repos/:owner/:repo/branches/:branch ``` 我们可以看到几个特性: * 资源分为单个文档和集合,尽量使用复数来表示资源,单个资源通过添加 id 或者 name 等来表示 * 一个资源可以有多个不同的 URL * 资源可以嵌套,通过类似目录路径的方式来表示,以体现它们之间的关系 最常见的一种设计错误,就是 URL 包含动词。因为” 资源” 表示一种实体,所以应该是名词,URL 不应该有动词,动词应该放在 HTTP Method (参考下一条)中。举例来说,某个 URL 是 `/users/show/1` ,其中 `show` 是动词,这个 URL 就设计错了,正确的写法应该是 `/users/1` ,然后用 HTTP GET 方法表示 show。 如果某些动作是 HTTP 动词表示不了的,你可以把动作看成是一种资源。比如网上汇款,从账户 1 向账户 2 汇款 500 元,错误的 URL 是: ``` POST /accounts/1/transfer/500/to/2 ``` 正确的写法是把动词 transfer 改成 transaction,资源不能是动词,但是可以是一种服务: ``` POST /transactoin HTTP/1.1 HOST: 127.0.0.1 from=1&to=2&amount=500 ``` 五、正确使用 HTTP Method ------------------ 有了资源的 URI 设计,所有针对资源的操作都是使用 HTTP 方法指定的。比较常用的 HTTP/1.1 动词有下面 5 个: * GET:从服务器取出资源(一项或多项)。 * POST:在服务器新建一个资源。 * PUT:在服务器更新资源(客户端提供改变后的完整资源)。 * PATCH:在服务器更新资源(更新资源的部分属性)。 * DELETE:从服务器删除资源。 还有 4 个不常用的 HTTP/1.1 动词: * HEAD:只获取某个资源的头部信息。比如只想了解某个文件的大小,某个资源的修改日期等 * OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。 * TRACE:追踪路径。不建议使用。 * CONNECT:要求用隧道协议连接代理。不建议使用。 举例: ``` GET /repos/:owner/:repo/issues GET /repos/:owner/:repo/issues/:number POST /repos/:owner/:repo/issues PATCH /repos/:owner/:repo/issues/:number DELETE /repos/:owner/:repo ``` 这里顺带探讨一下,HTTP 协议涉及到的一种重要性质:幂等性 (Idempotence)。在 HTTP/1.1 规范中幂等性的定义是: ``` Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. ``` 从定义上看,HTTP 方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。幂等性属于语义范畴,正如编译器只能帮助检查语法错误一样,HTTP 规范也没有办法通过消息格式等语法手段来定义它,这可能是它不太受到重视的原因之一。但实际上,幂等性是分布式系统设计中十分重要的概念,而 HTTP 的分布式本质也决定了它在 HTTP 中具有重要地位。 安全方法是指不修改资源的 HTTP 方法。譬如,当使用 GET 或者 HEAD 作为资源 URL,都必须不去改变资源。然而,这并不全准确。意思是:它不改变资源的表示形式。对于安全方法,它仍然可能改变服务器上的内容或资源,但这必须不导致不同的表现形式。 <table><thead><tr><th width="21%"></th><th width="37%">HTTP Method</th><th width="21%">幂等</th><th width="21%">安全</th></tr></thead><tbody><tr><td>1</td><td>OPTIONS</td><td>yes</td><td>yes</td></tr><tr><td>2</td><td>GET</td><td>yes</td><td>yes</td></tr><tr><td>3</td><td>HEAD</td><td>yes</td><td>yes</td></tr><tr><td>4</td><td>PUT</td><td>yes</td><td>no</td></tr><tr><td>5</td><td>POST</td><td>no</td><td>no</td></tr><tr><td>6</td><td>DELETE</td><td>yes</td><td>no</td></tr><tr><td>7</td><td>PATCH</td><td>no</td><td>no</td></tr></tbody></table> 实际上接口的幂等或者安全与否取决于接口的实现,只是 HTTP Method 语义上我们约定俗成地认为实现的过程会参照上表所示。对于幂等的接口,客户端就可以放心地多次调用,网关层面也可以重试。 六、状态码 (Status Code) ------------------- HTTP 应答中,需要带一个很重要的字段: `status code` 。它说明了请求的大致情况,是否正常完成、需要进一步处理、出现了什么错误,对于客户端非常重要。状态码都是三位的整数,大概分成了几个区间: ``` 2XX 3XX 4XX 5XX ``` 在 HTTP API 设计中,经常用到的状态码以及它们的意义如下表: <table><thead><tr><th width="18%">Status Code</th><th width="25%">语义</th><th width="57%">说明</th></tr></thead><tbody><tr><td>200</td><td>OK</td><td>请求已成功</td></tr><tr><td>201</td><td>Created</td><td>请求已完成,并导致了一个或者多个资源被创建,最常用在 POST 创建资源的时候</td></tr><tr><td>202</td><td>Accepted</td><td>请求已经接收并开始处理,但是处理还没有完成。一般用在异步处理的情况,响应 body 中应该告诉客户端去哪里查看任务的状态</td></tr><tr><td>204</td><td>No Content</td><td>请求已经处理完成,但是没有信息要返回,经常用在 PUT 更新资源的时候(客户端提供资源的所有属性,因此不需要服务端返回)。如果有重要的 metadata,可以放到头部返回</td></tr><tr><td>301</td><td>Moved Permanently</td><td>请求的资源已经永久性地移动到另外一个地方,后续所有的请求都应该直接访问新地址。服务端会把新地址写在 <code>Location</code> 头部字段,方便客户端使用。允许客户端把 POST 请求修改为 GET。</td></tr><tr><td>302</td><td>Moved Temporarily</td><td>临时重定向</td></tr><tr><td>304</td><td>Not Modified</td><td>请求的资源和之前的版本一样,没有发生改变。用来缓存资源,和条件性请求(conditional request)一起出现</td></tr><tr><td>307</td><td>Temporary Redirect</td><td>目标资源暂时性地移动到新的地址,客户端需要去新地址进行操作,但是 <strong>不能</strong> 修改请求的方法。</td></tr><tr><td>308</td><td>Permanent Redirect</td><td>和 301 类似,除了客户端 <strong>不能</strong> 修改原请求的方法</td></tr><tr><td>400</td><td>Bad Request</td><td>1. 语义有误,当前请求无法被服务器理解; 2. 请求参数有误。</td></tr><tr><td>401</td><td>Unauthorized</td><td>当前请求需要身份验证。</td></tr><tr><td>403</td><td>Forbidden</td><td>服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。</td></tr><tr><td>404</td><td>Not Found</td><td>请求失败,请求所希望得到的资源未被在服务器上发现。</td></tr><tr><td>405</td><td>Method Not Allowed</td><td>请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个 Allow 头信息用以表示出当前资源能够接受的请求方法的列表。鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回 405 错误。</td></tr><tr><td>406</td><td>Not Acceptable</td><td>请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。</td></tr><tr><td>409</td><td>Conflict</td><td>由于和被请求的资源的当前状态之间存在冲突,请求无法完成。</td></tr><tr><td>429</td><td>Too Many Requests</td><td>资源配额不足或达到速率限制。</td></tr><tr><td>499</td><td>Client Closed Request</td><td>请求被客户端取消。</td></tr><tr><td>500</td><td>Internal Server Error</td><td>服务器内部错误</td></tr><tr><td>501</td><td>Not Implemented</td><td>服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。</td></tr><tr><td>502</td><td>Bad Gateway</td><td>作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。</td></tr><tr><td>503</td><td>Service Unavailable</td><td>由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。</td></tr><tr><td>504</td><td>Gateway Timeout</td><td>作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如 DNS)收到响应。</td></tr><tr><td>505</td><td>HTTP Version Not Supported</td><td>服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。</td></tr></tbody></table> 上面这些状态码覆盖了 API 设计中大部分的情况,如果对某个状态码不清楚或者希望查看更完整的列表,可以参考 **HTTP Status Code** 、 **维基百科 - 状态码** 或者 **RFC7231 Response Status Codes** 的内容。 七、错误处理(Error Handling) ---------------------- 如果出错,应该在 response body 中通过 `message` 给出明确的错误信息(一般来说,返回的信息中将 message 作为键名,出错详情作为键值即可)。比如客户端发送的请求有错误,一般会返回 `4XX Bad Request` 结果。这个结果很模糊,给出错误 `message` 的话,能更好地让客户端知道具体哪里有问题,进行快速修改。 ``` { "message":"错误详情" } ``` 错误详情应该可以帮助用户轻松快捷地理解和解决 API 错误。通常,在编写错误详情时请考虑以下准则: * 不要假设用户是您 API 的专家用户。用户可能是客户端开发人员、操作人员、IT 人员或应用的最终用户。 * 不要假设用户了解有关服务实现的任何信息,或者熟悉错误的上下文(例如日志分析)。 * 如果可能,应构建错误详情,以便技术用户(但不一定是 API 开发人员)可以响应错误并改正。 * 确保错误详情内容简洁。如果需要,请提供一个链接,便于有疑问的读者提问、提供反馈或详细了解错误详情中不方便说明的信息。此外,可使用详细信息字段来提供更多信息。 八、命名规则 ------ 为了能够长时间在众多 API 中为开发者提供一致的体验,API 使用的所有名称都应该具有以下特点: * 简单 * 直观 * 一致 这包括接口、资源、集合、方法和消息的名称。 由于很多开发者不是以英语为母语,所以这些命名惯例的目标之一是确保大多数开发者可以轻松理解 API。对于方法和资源,我们鼓励使用简单、直观和少量的词汇来命名。 * API 名称 **应该** 使用正确的美式英语。例如,使用美式英语的 license、color,而非英式英语的 licence、colour。 * 为了简化命名, **可以** 使用已被广泛接受的简写形式或缩写。例如,API 优于 Application Programming Interface。 * 尽量使用直观、熟悉的术语。例如,如果描述移除(和销毁)一个资源,则删除优于擦除。 * 使用相同的名称或术语命名同样的概念,包括跨 API 共享的概念。 * 避免名称过载。使用不同的名称命名不同的概念。 * 避免在 API 的上下文以及更大的 API 生态系统中使用含糊不清且过于笼统的名称。这些名称可能导致对 API 概念的误解。相反,应选择能准确描述 API 概念的名称。这对定义一阶 API 元素(例如资源)的名称尤其重要。没有要避免使用的名称的明确列表,因为每个名称都必须放在其他名称的上下文中进行评估。实例、信息和服务是过去有问题的名称的示例。所选择的名称应清楚地描述 API 概念(例如:什么的实例?),并将其与其他相关概念区分开(例如:“alert” 是指规则、信号还是通知?)。 * 仔细考虑是否使用可能与常用编程语言中的关键字相冲突的名称。您可以使用这些名称,但在 API 审核期间可能会触发额外的审查。因此应谨慎使用。 九、认证和授权(Authentication & Authorization) --------------------------------------- 一般来说,让任何人随意访问公开的 API 是不好的做法。验证和授权是两件事情: * 验证(Authentication)是为了确定用户是其申明的身份,比如提供账户的密码。不然的话,任何人伪造成其他身份(比如其他用户或者管理员)是非常危险的 * 授权(Authorization)是为了保证用户有对请求资源特定操作的权限。比如用户的私人信息只能自己能访问,其他人无法看到;有些特殊的操作只能管理员可以操作,其他用户有只读的权限等等 如果没有通过验证(提供的用户名和密码不匹配,token 不正确等),需要返回 **401 Unauthorized** 状态码,并在 body 中说明具体的错误信息;而没有被授权访问的资源操作,需要返回 **403 Forbidden** 状态码,还有详细的错误信息。 NOTES: 借鉴于 Github,它对某些用户未被授权访问的资源操作返回 **404 Not Found** ,目的是为了防止私有资源的泄露(比如黑客可以自动化试探用户的私有资源,返回 403 的话,就等于告诉黑客用户有这些私有的资源)。 十、限流(RateLimit) --------------- 如果对访问的次数不加控制,很可能会造成 API 被滥用,甚至被 **DDOS 攻击** 。根据使用者不同的身份对其进行限流,可以防止这些情况,减少服务器的压力。 对用户的请求限流之后,要有方法告诉用户它的请求使用情况,本文档推荐使用的三个相关的头部: * `X-RateLimit-Limit` : 用户每个小时允许发送请求的最大值 * `X-RateLimit-Remaining` :当前时间窗口剩下的可用请求数目 * `X-RateLimit-Rest` : 时间窗口重置的时候,到这个时间点可用的请求数量就会变成 `X-RateLimit-Limit` 的值 举例: ``` X-Ratelimit-Limit: 18000 X-Ratelimit-Remaining: 17995 X-Ratelimit-Reset: 1590570990 ``` 如果允许没有登录的用户使用 API(可以让用户试用),可以把 `X-RateLimit-Limit` 的值设置得很小,比如 `60` 。没有登录的用户是按照请求的 IP 来确定的,而登录的用户按照认证后的信息来确定身份。 对于超过流量的请求,可以返回 **429 Too many requests** 状态码,并附带错误信息。 十一、编写优秀的文档 ---------- API 最终是给人使用的,不管是公司内部,还是公开的 API 都是一样。即使我们遵循了上面提到的所有规范,设计的 API 非常优雅,用户还是不知道怎么使用我们的 API。最后一步,但非常重要的一步是:为你的 API 编写优秀的文档。 对每个请求以及返回的参数给出说明,最好给出一个详细而完整地示例,提醒用户需要注意的地方…… 反正目标就是用户可以根据你的文档就能直接使用 API,而不是要发邮件给你,或者跑到你的座位上问你一堆问题。
yg9538
2022年8月15日 11:23
835
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档
PDF文档(打印)
分享
链接
类型
密码
更新密码