萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 開發 RESTful API 接口實戰:設計規範、參數驗證與簽名鑑權

API 接口設計核心原則

原則說明範例
資源導向URL 表達資源名詞,動詞由 HTTP Method 表示GET /api/v1/users/123
版本控制URL 包含版本號,便於迭代兼容/api/v1/、/api/v2/
統一響應格式固定結構,前端統一處理{code, message, data, meta}
狀態碼語義化HTTP Status Code 表達結果類別200/201/400/401/403/404/422/500
冪等性GET/PUT/DELETE 多次調用結果一致POST 非冪等

統一響應結構

<?php
// 成功響應
[
    'code' => 200,
    'message' => 'success',
    'data' => [...],  // 業務數據
    'meta' => [       // 分頁/額外元數據
        'page' => 1,
        'per_page' => 15,
        'total' => 100
    ]
]

// 失敗響應
[
    'code' => 422,
    'message' => '驗證失敗',
    'errors' => [
        'email' => ['郵箱格式不正確'],
        'password' => ['密碼長度至少 8 位']
    ]
]

基礎控制器封裝 (Laravel/ThinkPHP 風格)

<?php
namespace app\api\controller;

use think\facade\Request;
use think\facade\Validate;
use think\response\Json;

class BaseController
{
    protected function success($data = [], $message = 'success', $meta = []): Json
    {
        return json([
            'code' => 200,
            'message' => $message,
            'data' => $data,
            'meta' => $meta,
        ]);
    }

    protected function error($message = 'error', $code = 400, $errors = []): Json
    {
        return json([
            'code' => $code,
            'message' => $message,
            'errors' => $errors,
        ], $code);
    }

    protected function validate(array $rules, array $data = []): array
    {
        $validate = Validate::rule($rules);
        if (!$validate->check($data ?: Request::param())) {
            throw new \think\exception\ValidateException($validate->getError());
        }
        return $data ?: Request::param();
    }
}

實戰:用戶註冊接口

<?php
namespace app\api\controller\v1;

use app\api\controller\BaseController;
use app\model\User;
use think\facade\Db;

class Auth extends BaseController
{
    public function register()
    {
        // 1. 參數驗證
        $data = $this->validate([
            'username' => 'require|alphaNum|length:3,20|unique:user',
            'email' => 'require|email|unique:user',
            'password' => 'require|length:8,32|confirmed',  // 需傳 password_confirm
            'mobile' => 'require|regex:/^1[3-9]\d{9}$/|unique:user',
        ]);

        // 2. 業務處理 (事務)
        try {
            $user = Db::transaction(function () use ($data) {
                $user = User::create([
                    'username' => $data['username'],
                    'email' => $data['email'],
                    'password' => password_hash($data['password'], PASSWORD_DEFAULT),
                    'mobile' => $data['mobile'],
                    'status' => 1,
                ]);
                // 可擴展:發送歡迎郵件、初始化配置、記錄註冊日誌
                return $user;
            });

            return $this->success($user->hidden(['password'])->toArray(), '註冊成功');
        } catch (\Throwable $e) {
            return $this->error('註冊失敗:' . $e->getMessage(), 500);
        }
    }
}

簽名鑑權 (開放平台/第三方調用)

防篡改、防重放、身份驗證三合一:

簽名算法 (HMAC-SHA256)

<?php
function generateSign(array $params, string $secret, int $timestamp): string
{
    // 1. 過濾空值、sign 字段
    $params = array_filter($params, fn($v) => $v !== '' && $v !== null);
    unset($params['sign']);

    // 2. 字典序排序
    ksort($params);

    // 3. 拼裝字串: key1=value1&key2=value2...
    $string = http_build_query($params, '', '&', PHP_QUERY_RFC3986);

    // 4. 加入時間戳防重放 (5分鐘有效期)
    $string .= "×tamp=$timestamp";

    // 5. HMAC-SHA256
    return hash_hmac('sha256', $string, $secret);
}

// 驗證中間件
public function handle($request, \Closure $next)
{
    $timestamp = (int)$request->header('X-Timestamp');
    $sign = $request->header('X-Sign');
    $appId = $request->header('X-App-Id');

    // 時間戳檢查 (防重放)
    if (abs(time() - $timestamp) > 300) {
        return json(['code' => 401, 'message' => '請求已過期'], 401);
    }

    // 查詢 AppSecret
    $app = AppModel::where('app_id', $appId)->find();
    if (!$app) {
        return json(['code' => 401, 'message' => '無效的 AppID'], 401);
    }

    // 重新計算簽名比對
    $params = $request->param();
    $expectedSign = generateSign($params, $app->app_secret, $timestamp);
    if (!hash_equals($expectedSign, $sign)) {
        return json(['code' => 401, 'message' => '簽名驗證失敗'], 401);
    }

    // 防重放:Redis 存儲已用簽名 (key: sign:{sign}, ttl: 300s)
    if (Redis::exists("sign:$sign")) {
        return json(['code' => 401, 'message' => '重複請求'], 401);
    }
    Redis::setex("sign:$sign", 300, 1);

    return $next($request);
}

路由定義 (RESTful 風格)

// route/api.php
Route::group('v1', function () {
    Route::post('auth/register', 'v1.Auth/register');
    Route::post('auth/login', 'v1.Auth/login');
    
    Route::middleware('auth:api')->group(function () {
        Route::get('user/profile', 'v1.User/profile');
        Route::put('user/profile', 'v1.User/updateProfile');
        Route::apiResource('posts', 'v1.Post');  // 批量生成 index/create/store/show/update/destroy
    });
})->prefix('api');

文檔自動生成

  • Swagger/OpenAPI:swagger-php 註解生成 swagger.json,配合 Swagger UI
  • Apifox / Postman:導入導出、自動化測試、Mock 服務
  • RapiDoc / Redoc:靜態文檔頁面部署

效能優化清單

  • 關鍵查詢加索引、避免 N+1 問題 (Eager Loading)
  • 熱點數據 Redis 快取 (用戶資料、配置、權限)
  • 大數據導出異步任務佇列 + 分片下載
  • API 限流:Token Bucket / Leaky Bucket (Redis Lua 腳本實現)
  • 啟用 OPcache、JIT (PHP 8+)、預加載
copyright © 萬盛學電腦網 all rights reserved