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

相关文章
|
1月前
|
人工智能 前端开发 安全
AI直播数字人系统开发方案:企业如何搭建智能化直播平台
本文详解AI直播数字人系统的设计与实现,涵盖系统架构、核心模块(数字人/大模型/语音/中控/业务系统)、技术流程(从评论识别到口型同步)、知识库构建、安全审核及高并发应对等关键环节,助力企业打造自主可控的智能直播平台。(239字)
|
1月前
|
安全 API 定位技术
外卖系统接入配送API方案:如何实现订单与配送服务高效对接
本文详解外卖系统接入第三方配送API的完整方案,涵盖架构设计、接口规范、PHP代码实现、状态回调、幂等处理、异常重试及多平台适配等核心环节,助力自建平台高效解耦订单与履约,降低配送体系建设成本。(239字)
|
5月前
|
Rust JavaScript Java
PHP已死?谎言与真相:2025年PHP生态现状、薪资趋势与未来前景
每隔几年,技术圈就会响起“PHP已死”的论调。然而现实是,直至2025年,PHP仍然驱动着超过77%的网站,WordPress市场占有率持续攀升,Laravel和Symfony社区依然活跃。
671 0
|
7月前
|
消息中间件 算法 调度
外卖配送系统搭建方法核心:调度算法与任务分配机制实现思路
外卖配送系统的核心不在页面,而在调度算法。本文详解如何构建高效调度体系:从基础距离匹配、加权评分模型,到批量订单优化与微服务架构,涵盖数据模型、代码实现与生产实践,揭示智能调度才是决定履约效率与平台竞争力的关键壁垒。(239字)
|
8月前
|
人工智能 缓存 JSON
互联网医院AI问诊高并发场景下的性能优化方案
本文详解互联网医院AI问诊系统的高并发优化方案,涵盖架构解耦、限流降级、异步推理、分库分表、多级缓存、线程池调优、读写分离及AI服务独立部署等八大核心策略,并附可落地的代码示例,助系统从容应对多医院、多城市、大规模并发问诊场景。(239字)
|
5月前
|
消息中间件 人工智能 缓存
私域直播App搭建方案:大健康直播+商城模式如何实现
直播电商进入精细化运营阶段,大健康企业加速布局私域直播App:整合直播、商城、会员、健康档案与AI服务,实现用户沉淀、长期复购与数据化运营,构建“内容+服务+交易”闭环。(239字)
|
5月前
|
存储 小程序 前端开发
私域直播带货小程序怎么搭建?一套完整流程讲清楚
本文详解私域直播带货小程序搭建全流程:涵盖需求分析、技术选型、前后端架构设计,及直播播放、商品管理、微信支付、分销裂变、消息推送等核心模块,并提供关键代码示例与高并发、库存同步等实战注意事项。(239字)
|
4月前
|
缓存 小程序 NoSQL
外卖配送系统开发搭建从0到1:小程序、App与后台如何联动
本文深度解析外卖配送系统开发搭建的核心逻辑,聚焦“订单实时流转”这一关键——涵盖用户端下单、商家WebSocket接单、骑手定位调度、后台统一管控及高并发优化等全链路技术实现,揭示多端实时联动与智能调度的底层架构。(239字)
|
6月前
|
前端开发 NoSQL 数据库
直播带货系统搭建全流程拆解:私域直播如何实现稳定变现
在公域流量昂贵的今天,私域直播成为品牌稳定变现的关键——核心不在“播”,而在构建可控的用户、交易与营销闭环系统。本文从架构设计到高并发订单、用户沉淀、分销裂变等实战模块,讲透如何真正搭好一套能赚钱的直播带货系统。(239字)
|
6月前
|
缓存 小程序 算法
外卖配送小程序开发核心难点:调度系统与订单分发机制解析
外卖配送小程序开发的核心不在前端界面,而在后端两大能力:智能调度系统(决定配送效率)与科学订单分发机制(保障稳定性和骑手体验)。多数项目“能用但跑不动”,症结恰在此——缺乏多约束实时优化、动态评分派单、多单路径规划及高并发架构设计。