Python实现API开发的详细教程

发布时间:2026/10/16 8:17:03

Python实现API开发的详细教程 前言「写 API」这三个字里最容易被跳过的是「设计」二字。很多教程一上来就写app.route把接口跑通就算完结果做出来的东西能返回数据却没人愿意用它路径里有动词、状态码永远是 200、错误信息藏在正常响应体里调用方只能靠猜。这里要先纠正一个说法上的不准确REST 不是一种协议也不是一套必须照抄的接口清单它是一种架构风格。你完全可以写一个「用 HTTP 但不算 REST」的接口代码照样跑只是当接口数量涨到几十个时不遵守这套约定会让每个调用方都多写一堆特判。本文只讲设计层面的东西资源怎么变成 URL、方法怎么承载语义、状态码怎么表达结果、JSON 报文怎么组织、认证与会话的基本概念。示例用轻量框架搭骨架但真正要记的是约定不是框架。文中出现的框架都需要自行安装版本与参数一律以该框架的官方文档为准。一、资源与 URL把名词放进路径REST 的核心想法是接口暴露的对象是资源resource资源用 URL 来定位。既是资源就应该是名词而不是动词。设计URL 样子问题动词式/getBook?id42动作写进了路径加一个动作就要加一个路径动词式/deleteBook/42与 HTTP 方法语义重复资源式 ✅/api/books/42名词 标识动作交给 HTTP 方法几条实用规律集合用复数名词/api/books单个元素在其后加标识/api/books/42。从属关系用嵌套表达层级/api/books/42/reviews表示 42 号书的评论集合。查询、排序、分页用查询串不要塞进路径/api/books?authorlisipage2。路径里不要出现动词。/api/books/42/borrow这类「动作型子资源」在业务上不可避免时可以用但它属于例外不是常态。版本号放路径前缀/api/v1/books。这样将来不兼容的改动可以并存一段时间。二、HTTP 方法与状态码同一个 URL配不同的 HTTP 方法含义完全不同。这是 REST 最省事的地方——URL 只表达「对什么」方法表达「做什么」。方法语义安全幂等典型成功码GET读取资源是是200POST在集合中创建新资源否否201PUT整体替换某个资源否是200 或 204PATCH局部修改某个资源否否200 或 204DELETE删除某个资源否是204「安全safe」指这个方法不应改变服务器状态只读「幂等idempotent」指同样的请求执行一次和执行多次服务器最终状态相同。幂等这个概念值得多说一句因为它是初学者最容易踩的坑PUT和DELETE是幂等的意味着「把 42 号书替换成这份内容」重复发十次结果和发一次一样。而POST不幂等——「创建一本书」发十次就真的会有十本书。所以创建资源用POST不要用GET而重试逻辑只在幂等的方法上才安全。PUT与PATCH的区别在于「替换」还是「合并」PUT要求请求体是资源的完整表示没带上的字段会被清掉PATCH只改请求体里出现的字段。设计时选一个并写进文档不要在同一资源上混用出歧义。状态码把结果说清楚状态码是 HTTP 自带的「结果枚举」用好它调用方就不必解析响应体才知道发生了什么。状态码含义什么时候用200OK请求成功响应体里有数据201Created创建成功通常配Location头指向新资源204No Content成功但没有响应体DELETE常用400Bad Request请求格式有问题比如 JSON 都解析不了401Unauthorized未认证或者凭证无效403Forbidden已认证但没有权限404Not Found资源不存在405Method Not Allowed路径在但不支持这个方法409Conflict与当前资源状态冲突比如重名422Unprocessable Entity格式合法但字段校验不通过500Internal Server Error服务器内部出错不应泄露堆栈有一个反模式必须点出来所有请求都返回 200把业务错误写进响应体。这会让所有网关、监控、重试机制都失效——它们只看状态码。如果调用方拿到 200 还得解析 JSON 里的success字段才知道成不成功那你就把 HTTP 白用了。三、JSON 请求体与响应体JSON 已经是事实上的默认格式。要点有三条请求和响应都要带Content-Type: application/json否则对方不知道该按什么解析。请求体用POST/PUT/PATCH传不要用GET把一堆数据塞进查询串。字段命名风格全文统一要么全snake_case要么全camelCase不要一半一半。把 API 的读写串起来一个最小可用的例子是这样的# 适用于 Python 3.8需先安装 Flaskfrom flask import Flask, jsonify, requestapp Flask(__name__)BOOKS {1: {id: 1, title: Python 入门, price: 39.0}}next_id 2app.get(/api/books)def list_books():return jsonify(list(BOOKS.values())), 200app.get(/api/books/int:book_id)def get_book(book_id):book BOOKS.get(book_id)if book is None:return jsonify({error: book not found}), 404return jsonify(book), 200app.post(/api/books)def create_book():global next_iddata request.get_json(silentTrue)if not isinstance(data, dict) or title not in data:return jsonify({error: title is required}), 400book {id: next_id, title: data[title], price: data.get(price, 0.0)}BOOKS[next_id] booknext_id 1return jsonify(book), 201app.put(/api/books/int:book_id)def replace_book(book_id):if book_id not in BOOKS:return jsonify({error: book not found}), 404data request.get_json(silentTrue)if not isinstance(data, dict) or title not in data:return jsonify({error: title is required}), 400BOOKS[book_id] {id: book_id,title: data[title],price: data.get(price, 0.0),}return jsonify(BOOKS[book_id]), 200app.delete(/api/books/int:book_id)def delete_book(book_id):if BOOKS.pop(book_id, None) is None:return jsonify({error: book not found}), 404return , 204if __name__ __main__:app.run(debugTrue)app.get(...)/app.post(...)是 Flask 2.0 起提供的简写等价于app.route(..., methods[...])。返回元组(响应, 状态码)是框架约定的写法。如果想绕开框架、自己用标准库拼 JSON要记得ensure_ascii这个参数# 适用于 Python 3.7import jsondata {title: Python 入门, price: 39.0}text json.dumps(data, ensure_asciiFalse) # 保留中文原样print(text)# {title: Python 入门, price: 39.0}back json.loads(text)print(back[title]) # Python 入门json.dumps默认ensure_asciiTrue会把中文转成\uXXXX转义——功能上没错读起来很痛苦日志里排查问题时尤其明显。另外Python 的None会被序列化成 JSON 的null字典的键在序列化后一定是字符串这些细节写接口时要有数。FastAPI 这类较新的框架思路一致但通常把「路径参数、请求体模型、返回模型」都交给类型注解来描述并自动生成接口文档。它的具体装饰器写法、模型定义方式与参数名请以其官方文档为准本文不复述。四、认证与会话的基本概念先分清两个词认证authentication你是谁。授权authorization你能做什么。未登录是 401登录了但没权限是 403两者不要混。常见的两种做法方案凭证存哪服务器要不要存状态适合会话 Cookiesession浏览器自动带的 Cookie要服务端保存会话同域网页应用令牌token如 Bearer客户端自己保存并放进请求头通常不要靠签名校验跨端、移动端、服务间调用会话方案里服务器只在 Cookie 里放一个随机的会话 ID真正的用户信息存在服务端令牌方案里凭证本身就携带了身份信息通常是签名过的服务端验签即可。无论哪种都必须走 HTTPS——凭证在明文信道上传输等于没有。几条不能妥协的底线密码绝不能明文存储也不要自己发明加密方案。用标准库的hashlib.scrypt这类自带盐值的慢哈希函数或者成熟的密码哈希库具体参数以官方文档为准。令牌要用secrets模块生成不要用random——后者是可预测的伪随机数发生器用来生成凭证是安全隐患。比较令牌、签名这类敏感值用hmac.compare_digest做恒定时间比较避免因为比较耗时不同而泄露信息。认证信息不要放进 URL 查询串它会被记进服务器日志、浏览器历史和各种中间代理。常见坑点1. URL 里塞动词❌/api/getBookById?id42、/api/createBook。 ✅ 资源式/api/books/42GET/api/booksPOST动作交给方法。2. 一律返回 200❌ 找不到资源也返回200响应体里写{success: false}。 ✅ 找不到就404参数不合法就400创建成功就201状态码优先于响应体。3. 用GET做写操作❌GET /api/books/delete/42——爬虫和预取可能顺手就把数据删了。 ✅ 删除用DELETEGET保持只读。4. 分不清 401 和 403❌ 没登录和没权限都返回同一个码。 ✅ 未认证 401提示去登录已认证但无权 403提示找管理员。5. 把 500 的堆栈直接返回给调用方❌return str(traceback.format_exc()), 500把文件路径、库版本、SQL 语句全暴露出去。 ✅ 对外返回统一的错误结构堆栈只写进服务端日志。6. 中文 JSON 被转义后不便排查❌json.dumps(data)输出一堆中文。 ✅ 对外接口按需设置json.dumps(data, ensure_asciiFalse)并统一用 UTF-8 编码。7. 用random生成令牌❌token .join(random.choices(string.ascii_letters, k32))。 ✅ 用secrets.token_urlsafe()这类专为安全场景设计的接口。8. 用PUT却按PATCH的语义实现❌PUT只更新请求体里出现的字段没出现的保持不变。 ✅PUT表示整体替换缺的字段按「清空/默认值」处理要局部更新就用PATCH。总结设计维度一句话原则URL放名词放层级放版本号不放动词方法读用GET建用POST整体改用PUT局部改用PATCH删用DELETE状态码让 HTTP 状态码承载结果不要让调用方去解析业务字段报文JSON application/json命名风格统一中文别忘ensure_asciiFalse认证认证与授权分开凭证走 HTTPS密码慢哈希令牌用secretsAPI 设计的好坏短期看不出来长期体现在调用方的代码量上。当你的接口遵循「URL 是名词、方法是动词、状态码是结果」这三条调用方读一遍文档就能上手改起来也不容易出歧义。至于用哪个框架那只是实现细节——约定才是要守住的东西。
延伸阅读

更多相关文章

2026/10/16 8:17:03

基于JavaWeb的农产品电商后台管理系统设计与实现解析

每年到了毕业季,JavaWeb方向最不缺的就是后台管理系统类的选题。某高校软件工程专业的A同学今年拿到的题目是《基于JavaWeb的东北特色农产品电商后台管理系统》,从定题目到跑通整个项目,再到现在答辩通过,前后折腾了将近两个月。作…

2026/10/16 8:17:03

ReentrantLock底层源码解析:AQS队列与CAS锁机制深度剖析

ReentrantLock这个名字,搞Java并发的兄弟应该都不陌生。日常写多线程代码,synchronized用得多,但一旦涉及超时等待、可中断、公平性这些需求,ReentrantLock就是绕不开的替代方案。用起来简单,lock()和unlock()成对调用…

2026/10/16 8:12:03

PDF/Word一键转可编辑PPT:三层解析与AI语义压缩实践

很多做汇报材料的朋友都体会过这种痛苦:拿到一份行业白皮书或者内部制度文件,PDF有七十多页,每一段都写得密不透风。你需要从中划出五六个重点,换成口语化的表述,再用三四十页 PPT 把意思讲清楚。手动做这件事&#xf…

2026/10/16 10:18:30

基于Python的动漫分析系统全攻略:从数据采集到深度学习建模

很多同学在选毕设题目的时候,一眼就被“基于Python的动漫分析系统”这种题目抓住了眼球。原因很简单:动漫是兴趣,Python是上手快,深度学习是大热点,这三个词叠在一起,摆在任何一个答辩现场,都比…

2026/10/16 10:18:30

Micromine 2016实操:建模制图开发与Win10/11兼容性全解析

做矿业软件这一行,手里的工具版本常常比很多人的工作年限还要长。Micromine 2016就是这样的存在——我最早在一处铜多金属矿的储量复核项目里接触它,当时项目组的老工程师用它出图、建模,电脑还是老款的Win7工作站。几年过去,操作…

2026/10/16 10:18:30

WPF TreeView 拖拽实现详解:从原理到避坑指南

简介:这份资源面向具备一定 WPF 基础的开发者,聚焦 TreeView 控件的拖放(Drag & Drop)功能实现,解决节点顺序调整、数据移动与复制等交互需求。压缩包共 12 个文件,约 11KB,以 6 个 cs 源码…

2026/10/16 10:18:30

Qt程序打包如何补全版本与公司信息:从qmake到Inno Setup全配置

1. 为什么Qt程序默认打包出来是个"三无"安装包 先说个我自己的经历。之前给某公司做的一个模拟项目X收尾,Qt 5.15写的Windows桌面工具,编译、调试、跑自动化测试都通过了,最后用Inno Setup打了个安装包发给测试组。结果对方打开安装…

2026/10/16 10:18:30

YOLO免环境训练工具全流程指南:从自动标注到模型转换

简介:这份资源面向深度学习目标检测方向的开发者与算法学习者,提供一套免环境搭建的YOLO系列训练与标注工具,解决从数据标注到模型训练、转换流程繁琐的问题。包内共14个文件,以txt技术解析、html说明页、doc文档及jpg示意图为主&…

2026/10/16 10:13:29

Gitee不只能存代码:从SSH到Pull Request评审的团队协作进阶指南

如果你的日常工作流还停留在“把Gitee当成免费网盘,clone下来push上去就完事”,那你可能只用了这个代码托管平台一半以上的能力。我在过去几年带过好几个小团队,从最开始互相clone压缩包传文件,到后来把需求管理、代码评审、自动构…

2026/10/16 5:33:43

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/16 4:03:48

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/16 0:01:11

Cephadm实战指南:Linux系统工程师的生产级Ceph集群部署与排障

简介:本资源是一份完整的Ceph分布式存储系统中文技术文档合集,面向Linux系统运维工程师、云平台架构师及存储方向开发者,帮助读者系统掌握Ceph集群的部署、配置与运维核心能力。文档覆盖对象存储(RGW)、块设备&#xf…

2026/10/16 0:01:11

ITK中SpatialObject几何体系解析:坐标系、变换与管道集成

1. 空间对象的定位:为什么 ITK 需要一套几何描述体系很多刚开始接触 ITK 的朋友,包括我自己,最初都是被它的图像滤波、配准、分割这些“正统”功能吸引进来的。等真正上手做点实际项目,比如把分割出来的器官边界做量化分析、给血管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑