外卖系统接入配送API方案解析:打造订单与配送一体化管理平台

简介: 本文详解外卖系统接入配送API的完整方案,涵盖架构设计、统一接口、状态同步、回调幂等、异常处理及数据库建模等核心环节,助力订单与履约高效闭环。(238字)

随着外卖、同城零售以及本地生活服务的发展,订单履约已经成为平台运营中的重要环节。

传统外卖系统通常需要用户端、商家端、骑手端以及管理后台共同协作。当用户完成下单后,商家接单、配送派单、骑手取货、配送中、订单完成等环节都需要进行数据同步。

如果配送体系与订单系统相互独立,就容易出现订单状态不同步、配送信息更新滞后、人工派单效率低等问题。

因此,在外卖系统开发过程中,通过接入配送API,将订单中心与配送服务进行连接,可以让订单创建、配送派单、骑手状态以及配送结果形成完整的数据闭环。

本文将从系统架构、API设计、数据库设计以及核心代码几个方面,对外卖系统接入配送API的实现方案进行解析。
外卖系统.png

一、什么是外卖系统配送API

配送API主要用于连接外卖系统和第三方配送服务。

外卖系统负责用户下单、商家接单、订单管理等业务,而配送API负责将订单信息传递给配送服务,并接收配送服务返回的配送状态。

整体流程可以理解为:

用户端
  ↓
提交订单
  ↓
订单中心
  ↓
商家确认订单
  ↓
配送API
  ↓
创建配送任务
  ↓
配送服务
  ↓
骑手接单
  ↓
取货配送
  ↓
配送完成
  ↓
配送状态回传
  ↓
外卖订单更新

通过这种方式,可以把“订单管理”和“配送履约”连接起来。

二、外卖系统接入配送API的整体架构

一个比较完整的外卖配送架构,可以划分为以下几个模块:

┌────────────────────┐
│      用户端         │
│ H5 / 小程序 / APP   │
└─────────┬──────────┘
          │
          ↓
┌────────────────────┐
│      订单中心       │
│ 用户订单 / 商家订单 │
└─────────┬──────────┘
          │
          ↓
┌────────────────────┐
│     配送服务层      │
│ Delivery Service   │
└─────────┬──────────┘
          │
     ┌────┴─────┐
     ↓          ↓
配送API A    配送API B
     │          │
     └────┬─────┘
          ↓
      配送服务
          ↓
        骑手端

这里建议增加一个独立的“配送服务层”,而不是让订单业务直接调用第三方API。

这样做的好处是,当以后需要增加新的配送渠道时,不需要修改大量订单业务代码。

三、为什么需要独立的配送服务层

例如订单业务直接写成:

$api = new DeliveryApi();

$api->createOrder($order);

初期看起来比较简单,但是当平台同时接入多个配送服务后,代码可能逐渐变成:

if ($provider == 'A') {
   

    // 调用配送平台A

} elseif ($provider == 'B') {
   

    // 调用配送平台B

} elseif ($provider == 'C') {
   

    // 调用配送平台C
}

随着业务增长,这种方式会增加代码维护难度。

更合理的方式是建立统一接口。

interface DeliveryInterface
{
   
    public function createOrder(array $order);

    public function cancelOrder(string $deliveryNo);

    public function getOrder(string $deliveryNo);

    public function getDeliveryFee(array $params);
}

然后不同配送服务分别实现这个接口。

class ProviderA implements DeliveryInterface
{
   
    public function createOrder(array $order)
    {
   
        // 调用配送服务A
    }

    public function cancelOrder(string $deliveryNo)
    {
   
        // 取消配送服务A订单
    }

    public function getOrder(string $deliveryNo)
    {
   
        // 查询配送服务A订单
    }

    public function getDeliveryFee(array $params)
    {
   
        // 计算配送费用
    }
}

这样订单系统只需要调用统一方法:

$delivery->createOrder($order);

而不需要关心具体使用哪一个配送服务。

四、配送API需要设计哪些核心接口

外卖系统接入配送API时,通常需要围绕订单生命周期设计接口。

1. 配送费用查询

用户下单之前,可以根据商家地址和用户收货地址计算配送费用。

例如:

POST /api/delivery/fee

请求参数:

{
   
    "shop_lat": 45.123456,
    "shop_lng": 126.123456,
    "user_lat": 45.234567,
    "user_lng": 126.234567
}

返回:

{
   
    "code": 0,
    "delivery_fee": 6.00,
    "distance": 4.8
}

外卖系统可以根据返回结果向用户展示配送费用。

2. 创建配送订单

商家确认订单后,创建配送任务。

POST /api/delivery/order/create

请求:

{
   
    "order_no": "WM202609030001",
    "shop_name": "XX餐饮店",
    "shop_phone": "13800000000",
    "shop_address": "中央大街100号",
    "user_name": "张先生",
    "user_phone": "13900000000",
    "user_address": "幸福小区5号楼",
    "goods_amount": 58.00,
    "delivery_fee": 6.00,
    "remark": "请提前联系"
}

返回:

{
   
    "code": 0,
    "message": "success",
    "delivery_no": "PS202609030001"
}

外卖系统需要将delivery_no保存到数据库。

3. 查询配送订单

GET /api/delivery/order/detail

请求:

{
   
    "delivery_no": "PS202609030001"
}

返回:

{
   
    "code": 0,
    "delivery_no": "PS202609030001",
    "status": "delivering",
    "rider_name": "李师傅",
    "rider_phone": "13812345678"
}

4. 取消配送订单

如果用户取消订单或者商家无法正常出餐,可以调用取消配送接口。

POST /api/delivery/order/cancel

请求:

{
   
    "order_no": "WM202609030001",
    "delivery_no": "PS202609030001",
    "reason": "用户取消订单"
}

五、PHP实现配送API请求封装

以PHP为例,可以将HTTP请求统一封装。

class DeliveryClient
{
   
    private string $baseUrl;
    private string $appKey;
    private string $appSecret;

    public function __construct()
    {
   
        $this->baseUrl = 'https://api.example.com';
        $this->appKey = getenv('DELIVERY_APP_KEY');
        $this->appSecret = getenv('DELIVERY_APP_SECRET');
    }

    public function post(string $path, array $data)
    {
   
        $timestamp = time();

        $body = json_encode(
            $data,
            JSON_UNESCAPED_UNICODE
        );

        $sign = hash(
            'sha256',
            $this->appKey .
            $timestamp .
            $body .
            $this->appSecret
        );

        $headers = [
            'Content-Type: application/json',
            'X-App-Key: ' . $this->appKey,
            'X-Timestamp: ' . $timestamp,
            'X-Sign: ' . $sign
        ];

        $ch = curl_init();

        curl_setopt_array($ch, [
            CURLOPT_URL => $this->baseUrl . $path,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $body,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_TIMEOUT => 10
        ]);

        $result = curl_exec($ch);

        if ($result === false) {
   
            throw new RuntimeException(
                curl_error($ch)
            );
        }

        curl_close($ch);

        return json_decode($result, true);
    }
}

这里将APP_KEYAPP_SECRET放到环境变量中,可以避免把敏感配置直接写在源代码里。

六、创建配送订单

当商家完成接单后,可以创建配送订单。

$order = [
    'order_no' => 'WM202609030001',
    'shop_name' => 'XX餐饮店',
    'shop_phone' => '13800000000',
    'shop_address' => '中央大街100号',
    'user_name' => '张先生',
    'user_phone' => '13900000000',
    'user_address' => '幸福小区5号楼',
    'goods_amount' => 58,
    'delivery_fee' => 6,
    'remark' => '请提前联系'
];

$client = new DeliveryClient();

$result = $client->post(
    '/api/delivery/order/create',
    $order
);

if (($result['code'] ?? -1) === 0) {
   

    $deliveryNo = $result['delivery_no'];

    // 保存配送单号
    saveDeliveryOrder(
        $order['order_no'],
        $deliveryNo
    );
}

这里最重要的是建立“外卖订单号”和“配送订单号”的关联关系。

例如:

外卖订单号:
WM202609030001

配送订单号:
PS202609030001

后续查询配送状态、取消配送以及处理回调时,都可以通过这个关系找到对应订单。

七、数据库设计

可以单独建立配送订单表。

CREATE TABLE `order_delivery` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `order_id` BIGINT UNSIGNED NOT NULL,
    `order_no` VARCHAR(64) NOT NULL,
    `delivery_no` VARCHAR(64) DEFAULT NULL,
    `provider` VARCHAR(32) DEFAULT NULL,
    `status` VARCHAR(32) DEFAULT 'pending',
    `rider_name` VARCHAR(50) DEFAULT NULL,
    `rider_phone` VARCHAR(30) DEFAULT NULL,
    `distance` DECIMAL(10,2) DEFAULT 0,
    `delivery_fee` DECIMAL(10,2) DEFAULT 0,
    `created_at` DATETIME NOT NULL,
    `updated_at` DATETIME NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_order_no` (`order_no`),
    KEY `idx_delivery_no` (`delivery_no`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4;

通过单独的配送表,可以避免将大量配送字段直接堆积到订单表中。

八、配送状态统一

不同配送服务的状态名称可能并不一致。

例如服务A可能返回:

WAITING
TAKEN
PICKED
DELIVERING
FINISHED

服务B可能返回:

pending
accepted
picked_up
delivering
completed

因此系统内部最好建立统一状态。

例如:

const DELIVERY_PENDING = 'pending';
const DELIVERY_ACCEPTED = 'accepted';
const DELIVERY_PICKED_UP = 'picked_up';
const DELIVERY_DELIVERING = 'delivering';
const DELIVERY_COMPLETED = 'completed';
const DELIVERY_CANCELLED = 'cancelled';

然后进行状态转换:

function normalizeStatus(string $status): string
{
   
    $map = [
        'WAITING' => 'pending',
        'TAKEN' => 'accepted',
        'PICKED' => 'picked_up',
        'DELIVERING' => 'delivering',
        'FINISHED' => 'completed'
    ];

    return $map[$status] ?? 'unknown';
}

这样无论后台接入多少配送服务,用户端看到的订单状态都是统一的。

九、通过回调实现配送状态同步

配送API对接中,一个非常重要的功能就是回调。

例如骑手已经接单,配送服务主动通知外卖系统:

POST /api/delivery/callback

请求:

{
   
    "delivery_no": "PS202609030001",
    "order_no": "WM202609030001",
    "status": "accepted",
    "rider_name": "李师傅",
    "rider_phone": "13812345678",
    "event_id": "EV202609030001"
}

后端收到之后:

public function callback()
{
   
    $body = file_get_contents(
        'php://input'
    );

    $data = json_decode(
        $body,
        true
    );

    if (!$data) {
   
        return response()->json([
            'code' => 400,
            'message' => 'Invalid request'
        ]);
    }

    if (!$this->verifySignature($data)) {
   
        return response()->json([
            'code' => 401,
            'message' => 'Invalid signature'
        ]);
    }

    $deliveryNo = $data['delivery_no'];
    $status = normalizeStatus(
        $data['status']
    );

    $delivery = DeliveryOrder::where(
        'delivery_no',
        $deliveryNo
    )->first();

    if (!$delivery) {
   
        return response()->json([
            'code' => 404,
            'message' => 'Order not found'
        ]);
    }

    $delivery->status = $status;
    $delivery->rider_name =
        $data['rider_name'] ?? '';

    $delivery->rider_phone =
        $data['rider_phone'] ?? '';

    $delivery->save();

    $this->syncOrderStatus(
        $delivery->order_no,
        $status
    );

    return response()->json([
        'code' => 0,
        'message' => 'success'
    ]);
}

这样配送平台发生状态变化时,外卖系统就能够及时更新。

十、为什么必须处理回调幂等

实际网络环境中,一个回调可能被重复发送。

例如:

配送平台
   ↓
发送“配送完成”
   ↓
外卖系统已经处理
   ↓
网络响应失败
   ↓
配送平台再次发送
   ↓
外卖系统再次处理

如果没有幂等机制,就可能出现重复结算、重复发送通知等问题。

可以利用事件ID建立唯一索引。

ALTER TABLE `delivery_event`
ADD UNIQUE KEY `uk_event_id` (`event_id`);

处理回调时:

$exists = DeliveryEvent::where(
    'event_id',
    $data['event_id']
)->exists();

if ($exists) {
   
    return response()->json([
        'code' => 0,
        'message' => 'already processed'
    ]);
}

然后再保存事件:

DeliveryEvent::create([
    'event_id' => $data['event_id'],
    'delivery_no' => $data['delivery_no'],
    'status' => $data['status']
]);

这样即使同一个回调发送多次,也只会执行一次业务逻辑。

十一、配送费用计算

除了配送订单创建之外,配送费用也是外卖系统的重要组成部分。

可以根据业务规则设计:

配送费 =
基础配送费
+
距离费用
+
高峰时段附加费
+
特殊区域费用

例如:

function calculateDeliveryFee(
    float $baseFee,
    float $distance,
    float $unitPrice,
    float $timeFee = 0,
    float $areaFee = 0
): float {
   

    $distanceFee = 0;

    $freeDistance = 3;

    if ($distance > $freeDistance) {
   

        $extraDistance =
            $distance - $freeDistance;

        $distanceFee =
            $extraDistance * $unitPrice;
    }

    return round(
        $baseFee
        + $distanceFee
        + $timeFee
        + $areaFee,
        2
    );
}

例如:

$fee = calculateDeliveryFee(
    5,
    6,
    1.5,
    2,
    0
);

echo $fee;

在实际系统中,可以将这些参数放到后台配置中,让平台运营人员根据配送区域、时间段以及业务规则进行调整。

十二、配送异常处理

API并不是每一次调用都能够成功。

系统需要考虑:

接口超时
网络异常
参数错误
配送区域不支持
骑手无法接单
配送服务繁忙
配送订单取消失败
配送订单重复创建
回调通知失败

因此建议建立配送任务状态:

待创建
创建中
创建成功
创建失败
配送中
配送完成
取消中
已取消
异常

同时建立API日志:

CREATE TABLE `delivery_api_log` (
    `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    `order_no` VARCHAR(64) DEFAULT NULL,
    `delivery_no` VARCHAR(64) DEFAULT NULL,
    `api_path` VARCHAR(255) NOT NULL,
    `request_data` TEXT,
    `response_data` TEXT,
    `http_code` INT DEFAULT 0,
    `cost_time` INT DEFAULT 0,
    `created_at` DATETIME NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4;

通过日志可以快速定位:

哪个订单出了问题
调用了哪个接口
发送了什么参数
第三方返回了什么结果
接口耗时多久
是否发生重试

十三、使用队列提升系统稳定性

如果订单量比较大,不建议让用户下单请求直接等待配送API响应。

例如:

用户支付
  ↓
订单生成
  ↓
提交配送任务
  ↓
立即返回

可以改成:

用户支付
  ↓
订单生成
  ↓
创建配送任务
  ↓
消息队列
  ↓
配送服务Worker
  ↓
调用配送API

例如:

CreateDeliveryJob::dispatch(
    $order->id
);

Worker执行:

class CreateDeliveryJob
{
   
    public function handle()
    {
   
        $order = Order::find(
            $this->orderId
        );

        if (!$order) {
   
            return;
        }

        $delivery = app(
            DeliveryService::class
        );

        $delivery->createOrder(
            $order
        );
    }
}

这样可以降低第三方API响应速度对订单系统的影响。

十四、配送轨迹数据

如果配送服务能够提供骑手位置或配送轨迹接口,外卖系统还可以进一步实现配送地图。

例如:

{
   
    "rider_name": "李师傅",
    "status": "delivering",
    "latitude": 45.123456,
    "longitude": 126.123456,
    "updated_at": "2026-09-03 14:20:00"
}

用户端可以根据经纬度展示:

商家位置
   ↓
骑手当前位置
   ↓
用户收货位置

从而实现类似“骑手实时配送”的功能。

需要注意的是,位置数据更新频率、存储策略以及隐私保护都应该根据具体配送服务的能力和业务需求进行设计。

十五、后台如何管理配送订单

对于平台管理后台,可以设计独立的配送管理模块。

例如:

配送管理
├── 配送订单
├── 待配送订单
├── 配送中订单
├── 已完成订单
├── 异常配送
├── 配送服务配置
├── 配送费用规则
├── API日志
└── 配送数据统计

配送订单列表可以展示:

订单编号
商家名称
用户信息
配送地址
配送费用
配送状态
骑手信息
创建时间
配送完成时间

这样运营人员可以从后台统一查看订单和配送情况。

十六、打造订单与配送一体化闭环

完成API接入后,可以形成完整的业务闭环:

用户下单
   ↓
订单创建
   ↓
支付成功
   ↓
商家接单
   ↓
配送费用确认
   ↓
创建配送任务
   ↓
配送平台派单
   ↓
骑手接单
   ↓
骑手取货
   ↓
配送中
   ↓
用户收货
   ↓
配送完成
   ↓
订单完成
   ↓
数据统计

与此同时,订单、配送、骑手以及用户端的数据可以进行统一管理。

十七、外卖系统接入配送API的核心价值

从系统建设角度来看,配送API并不仅仅是增加一个“配送接口”,而是将订单系统与履约体系连接起来。

通过合理设计,可以实现:

订单自动流转

商家确认订单后自动创建配送任务,减少人工操作。

配送状态同步

骑手接单、取货、配送以及完成等状态可以实时同步。

多配送渠道扩展

通过统一配送接口,可以根据业务需求扩展不同配送服务。

配送费用统一管理

平台可以根据距离、区域、时间段等规则进行配送费用管理。

异常订单统一处理

通过API日志、任务队列和异常状态,可以快速定位配送问题。

数据统一沉淀

订单、配送、骑手以及配送费用等数据可以在平台后台统一统计。

外卖系统.png

十八、总结

外卖系统接入配送API的核心目标,是打通订单与配送之间的数据链路,让用户下单、商家接单、配送派单、骑手履约以及订单完成形成完整闭环。

在具体开发过程中,可以采用“订单中心 + 配送服务层 + API适配器 + 回调机制 + 消息队列”的架构,将核心业务与第三方配送服务进行解耦。

一个成熟的外卖系统配送架构可以概括为:

订单中心
    ↓
配送服务层
    ↓
API适配器
    ↓
第三方配送服务
    ↓
骑手履约
    ↓
配送状态回调
    ↓
订单状态同步
    ↓
用户端 / 商家端 / 管理后台

这种架构不仅能够满足当前外卖订单的配送需求,也能够为后续扩展跑腿、同城配送、即时零售等业务提供基础。

因此,在进行外卖系统开发时,配送API最好不要作为一个简单的附加功能进行开发,而应该将其作为订单履约体系的重要组成部分,通过标准化接口、统一状态、幂等机制、异常处理和数据日志等技术手段,打造更加稳定、高效的订单与配送一体化管理平台。

相关文章
|
20天前
|
人工智能 缓存 前端开发
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了
DeepSeek Harness + DeepSeek V4 Pro 项目实战保姆级教程!手把手带你从零安装开源 AI 编程工具,开发架构图、知识讲解网站、3D 网页游戏、全栈 AI 应用 4 个项目,覆盖运行模式选择、插件安装与开发,看看能不能对标 Claude。
13231 90
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了
|
8天前
|
人工智能 自然语言处理 安全
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
本文聚焦阿里云2026年推出的三款自研AI办公产品,清晰拆解千问办公、Qoder Teams、Qoder CN的差异化定位与能力边界:千问办公主打职场全场景提效,支持自然语言指令一键完成PPT生成、数据分析等高频办公任务;Qoder Teams面向程序员团队,深度整合AI代码生成、团队协同与企业知识库能力;Qoder CN则专为金融、政务等强合规场景打造,实现数据不出境与VPC私有化部署。文章同步给出分场景选型指南与最新活动定价,帮助不同类型的企业按需组合产品,实现业务岗、研发岗与强合规场景的AI能力全覆盖。
阿里云千问办公、Qoder Teams、Qoder CN区别与选择指南:模型能力、适用场景与最新活动参考
|
3天前
|
缓存 人工智能 API
阿里云Qwen3.8‑Flash完整能力解析:模型特性、API调用实操与计费规则深度拆解
在AI应用快速落地的当下,开发者与企业选型大模型API,不再只单纯关注评测榜单分数,推理速度、上下文长度、多模态能力、工具调用稳定性以及实际调用成本,共同决定项目能否平稳上线。Qwen3.8‑Flash作为新一代多模态混合专家模型,主打高性能推理与低成本开销,面向编程开发、智能Agent工作流、超长文档解析、图文混合理解等高频场景,提供托管API服务,权重同时开放可供本地部署,兼容主流接口协议,能够无缝接入各类开发工具链。很多开发者在接入过程中,容易混淆普通按量Token计费、缓存计费、各类订阅计划之间的差异,造成实际账单超出预估。本文从模型底层架构、核心功能能力、适用场景、API调用实操、完
801 0
|
13天前
|
Web App开发 人工智能 API
16 个超火的 DeepSeek Harness 插件,大肥鱼已经落后 N 个版本了。。。
DeepSeek Harness 精选插件推荐合集,从图片识别、浏览器操控、多 Agent 协作到手机远程控制,一口气带你看完 DSH 社区热门的十几个插件,覆盖技能扩展、UI 界面增强、整活玩法三大类,让你的鲸鱼变得更强。
1792 4
|
14天前
|
人工智能 Java BI
【AI】DeepSeek Harness 安装、运行、管理插件
本文介绍了如何运行DeepSeek开源的Agent框架DeepSeek Harness(dsh)。主要内容包括:使用nvm安装适配的Node版本;通过代理加速克隆GitHub源码;使用pnpm安装依赖并启动项目;配置DeepSeek API Token;安装扩展功能的插件。该框架自带Web界面,支持模型适配、文件编辑等插件化功能
1969 1
|
人工智能 JavaScript 开发工具
DeepSeek Harness 本地安装与使用指南
DeepSeek Harness(DSH)是DeepSeek AI开源的Agent运行框架,支持本地文件操作、命令执行与工具调用。基于Cordis插件架构,具备高扩展性与强可控性,适合开发者搭建可控Agent环境或开展模型基准测试。当前为开发者预览版,需Node.js环境,推荐先用`npx @deepseek-ai/dsh web`快速体验。
5230 0
|
9天前
|
人工智能 Linux iOS开发
Ollama使用教程:Ollama官网下载、Ollama本地部署大模型(2026最新)
Ollama 是一款免费开源的本地大模型运行工具,支持在 Windows/macOS/Linux 上离线运行 Qwen、DeepSeek、Llama 等主流开源模型,数据不出本机、隐私安全。提供 OpenAI 兼容 API,命令行一键拉取/运行/管理模型,无需联网,无调用限制,是开发者与 AI 爱好者部署本地 AI 助手的理想选择。(239 字)
|
16天前
|
人工智能 JavaScript 测试技术
保姆级教程:DeepSeek Harness从安装到跑通测试,30分钟上手
DeepSeek Harness是DeepSeek开源的AI Agent运行时,主打“一行命令安装、5分钟跑通”。它让模型真正动手干活——读代码、跑测试、分析失败、生成修复方案。本文手把手教你30分钟从零上手,覆盖安装、配置、实测及避坑指南,助你快速掌握下一代AI编程范式。
|
6天前
|
人工智能 监控 测试技术
Qwen3.8-Flash 来了,100万上下文、Agent、Coding 都加强了
8月26日,通义千问发布Qwen3.8-Flash-Next:125B参数、每Token仅激活6B,原生支持26万Token、可扩展至100万上下文;Coding、Agent与工具调用能力显著增强,面向真实软件工程任务,推动大模型从“回答问题”迈向“完成工作”。

热门文章

最新文章