这套 API 是什么
DouPHP 系统内置一套完整的 JSON API(约 200+ 端点),统一走 api/ 入口,最初服务于系统自带小程序,现已按「通用 API」标准补齐跨域、鉴权与错误规范,可以直接供 Vue / React 等浏览器端 SPA、移动 App、桌面客户端等任意客户端调用。
一句话理解:所有业务模块(文章、商品、订单、会员、预约、AI 助手等)都有一份对应的 JSON 接口,同一套令牌体系、同一套错误信封、同一套分页约定。
基础地址
API 统一入口为站点根目录下的 api/:
| 环境 | 基础地址(Base URL) | 完整示例 |
|---|---|---|
| 生产(伪静态) | https://example.com/api |
https://example.com/api/user/login_post |
| 生产(兼容形态) | https://example.com/api/ |
https://example.com/api/?route=user/login_post |
| 本地开发 | http://localhost/douphp.dou/api/ |
http://localhost/douphp.dou/api/?route=user/login_post |
两种形态完全等价:站点根目录 .htaccess 会把 ^api/(.+)$ 重写为 api/index.php?route=$1。推荐使用伪静态路径形态;若服务器未开启重写,退化为 ?route= 查询形态即可。
路径中的 route 段即接口标识,如:
api / user / login_post
│ │ └─ 动作(action)
│ └─ 模块(module)
└─ API 入口
部分接口在模块后还有子控制器层,如 api/order/cart/store(订单模块-购物车子控制器-添加)。路径末尾的纯数字自动识别为资源 ID,如 api/product/show/12 等价于 api/product/show?id=12。
统一响应信封
所有接口(含错误)一律返回如下 JSON 结构,HTTP 状态码与 code 双重表达结果:
{
"code": "OK",
"message": "",
"data": { },
"errors": { },
"request_id": "9f2a5c8e1b3d7f40"
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
string | 业务码。成功恒为 OK;失败为 UNAUTHORIZED、NOT_FOUND 等,详见《错误码与限流》 |
message |
string | 人类可读提示文案。客户端不得依赖文案分支判断,只用于展示 |
data |
object | 业务数据载体;无数据时固定为 {}(保证永远是对象,不会出现 []) |
errors |
object | 字段级校验错误集合,键=字段名、值=错误文案;无错误固定 {} |
request_id |
string | 请求追踪 ID(16 位十六进制),排查问题时提供给服务端定位日志 |
请求约定
-
请求体:
Content-Type: application/json时自动解析 JSON body;传统表单(application/x-www-form-urlencoded)同样支持。POST 接口两种均可。 -
查询参数:列表筛选、分页等走 query string,如
?page=2&category_id=3。 -
HTTP 方法:接口遵循 REST 语义(GET 读 / POST 建 / PUT、PATCH 改 / DELETE 删)。
-
方法伪装:部分环境(如部分网关、老客户端)不便发 PUT/DELETE,可在 POST 请求中伪装:
- Body 携带
_method=PUT,或 - Header 携带
X-HTTP-Method-Override: DELETE
两者优先级:Body
_method> Header。 - Body 携带
-
字符编码:UTF-8;响应统一
application/json; charset=utf-8。
分页约定
列表类接口统一使用 page 参数(从 1 开始),响应中返回总额与分页信息(具体字段以各模块文档为准):
GET /api/article?page=2
分页参数与页码信息在各模块的列表接口中结构一致:count(总数)、page(当前页)、page_size(每页数)、page_count(总页数);其中与小程序端兼容的接口还会附带 page_json 等预渲染字段。
鉴权一览
大多数写操作与「我的」数据需要登录,通过 Authorization 请求头携带 Bearer Token:
Authorization: Bearer <64位十六进制token>
- 登录成功(账号密码 / 手机验证码 / 注册)后由响应
data.user.token下发,有效期 30 天,每次调用自动续期活动时间。 - 退出登录调
user/logout吊销当前 token。 - 各接口的鉴权级别(公开 / 可选 / 必须)见各模块文档的「接口一览表」。三种级别含义:
- 公开:无须 token,匿名可调;
- 可选:带 token 返回个性化数据,不带也能调(如文章详情里判断是否已收藏);
- 必须:无有效 token 返回 401
UNAUTHORIZED。
详见《鉴权与会话》。
跨域(CORS)
浏览器端 SPA(Vue 等)跨域调用需要在服务端 config/security.php 中开启 CORS(默认关闭,零行为变化):
'cors' => [
'enabled' => true,
'allowed_origins' => ['https://your-vue-app.com', 'http://localhost:5173'],
'credentials' => false, // 需携带 Cookie 会话(结算等)时设为 true
],
- 命中白名单的预检请求(OPTIONS)返回
204并带全套Access-Control-Allow-*头; - 实际请求响应自动带
Access-Control-Allow-Origin;未命中的 Origin 不返回任何 CORS 头,浏览器自行拦截; - 小程序
wx.request不发Origin头,CORS 全链路 no-op,不受影响; credentials为true时不允许白名单用*,且前端需以withCredentials: true发起请求。
限流
防暴力破解类接口(登录、注册、发送验证码等)带定向限流,超限返回 HTTP 429 + code: RATE_LIMITED,并附 Retry-After 响应头(单位:秒)。全表见《错误码与限流》。
快速开始(axios)
import axios from 'axios'
const api = axios.create({
baseURL: 'https://example.com/api/',
timeout: 15000,
// 跨域 + Cookie 会话(结算流程)时开启:
// withCredentials: true,
})
// 请求拦截:自动附加令牌
api.interceptors.request.use((config) => {
const token = localStorage.getItem('api_token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
// 响应拦截:解信封 + 统一错误处理
api.interceptors.response.use(
(res) => {
const { code, message, data } = res.data
if (code === 'OK') return data
return Promise.reject(Object.assign(new Error(message), res.data))
},
(err) => {
const payload = err.response && err.response.data
if (payload && payload.code === 'UNAUTHORIZED') {
// 令牌失效:清本地并跳登录
localStorage.removeItem('api_token')
}
return Promise.reject(Object.assign(err, { payload }))
}
)
// 示例:账号密码登录
async function login(username, password) {
const data = await api.post('user/login_post', { username, password })
localStorage.setItem('api_token', data.user.token)
return data.user
}
// 示例:文章列表(第 1 页)
const list = await api.get('article', { params: { page: 1 } })
提示:URL 形态二选一时,
baseURL建议用带/api/的兼容形态(https://example.com/api/),此时相对路径user/login_post两种服务器环境都能工作。
客户端接入检查清单
- 打开 CORS 白名单并登记你的前端域名(浏览器端);
- 实现信封解包与 401 统一跳登录;
- 登录后持久化
data.user.token,请求时带Authorization: Bearer; - 列表页实现
page翻页; - 429 时按
Retry-After秒数退避重试; - 异常时记录
request_id便于服务端排查; - 涉及结算(下单、优惠券、运费)的客户端若走浏览器,需开启
credentials并使用withCredentials(该链路依赖 Cookie 会话,详见《客户端约定与扩展字段》)。