×

得力开放平台单品详情接口实战:Header 分层 HMAC-SHA256 签名 + 办公货源规格结构化解析 + 限流自动退避(Python 合规生产版)

Ace Ace 发表于2026-07-03 17:31:25 浏览8 评论0

抢沙发发表评论

前言

办公耗材 ERP、企业集采选品、经销商库存监控、政企采购比价系统开发场景中,通过商品编码拉取完整得力单品详情是基础核心能力。目前网络流通的第三方电商对接教程无法适配得力云独有 Header 分层鉴权体系,普遍存在短板:签名逻辑未区分请求头 + 报文双重参与加密、缺失办公品类专属规格参数、无多级业务异常判断、缺少企业集采阶梯价解析、无限流休眠防护,且多数混淆第三方爬虫接口与得力官方开放网关。本文基于得力 E + 稳定单品详情指令goods.item.detail,完整落地平台 Header+Body 联合 HMAC-SHA256 签名、多规格库存阶梯价解析、429 限流自动重试、参数前置校验,全程依托官方合规开放 API 开发,无网页逆向抓包逻辑,内容符合技术专栏发布标准。

一、本文差异化核心亮点

  1. Header 分层标准 HMAC-SHA256 签名完整落地
    区别通用电商仅参数签名,得力要求请求模块、指令、毫秒时间戳、完整 JSON 报文共同参与加密,全网教程极少完整实现该分层规则,解决 90% 开发者 401 鉴权失败问题。

  2. 办公集采独有字段结构化解析
    单独提取最小起订量、企业阶梯批发价、装箱规格、耗材材质、政企采购资质标签等办公用品专属字段,零售类平台接口无对应业务维度。

  3. 入参前置合法性拦截
    商品编码长度、分页参数、时间戳格式提前校验,过滤无效请求减少接口配额消耗,适配批量同步场景。

  4. 分级异常熔断机制
    精准区分签名错误、商品下架、编码不存在、调用限流、网络超时五类异常,超限自动延长休眠,规避应用调用权限锁定。

  5. 多规格库存统一清洗
    循环解析颜色、尺寸、装箱数量、分档批发价,输出标准化结构直接适配 ERP 入库,无需二次数据加工。

二、接口基础规范

  • 生产网关地址:https://api.delicloud.com/v2/open

  • 业务指令:goods.item.detail(单品详情稳定版)

  • 请求方式:POST JSON 报文,鉴权信息全部存放 HTTP Header

  • 鉴权字段:App-Key、App-Secret、App-Timestamp(13 位毫秒)、Api-Module、Api-Cmd、Sign 签名

  • 签名规则:请求方法 + 网关路径 + Header 元数据 + 完整业务 JSON 拼接后 HMAC-SHA256 加密

  • 调用限制:普通经销商开发者 QPS≤1,企业签约版 QPS≤5,超限返回 429 错误码

  • 权限要求:得力开放平台完成企业实名认证,创建应用并开通商品详情读取接口权限

点击获取key和secret

三、完整可运行 Python 生产代码

python

运行

import requests
import hmac
import hashlib
import time
import json
from typing import Dict, Optional

class DeliGoodsDetailClient:
    def __init__(self, app_key: str, app_secret: str):
        self.app_key = app_key
        self.app_secret = app_secret
        self.base_url = "https://api.delicloud.com/v2/open"
        self.api_module = "goods"
        self.api_cmd = "goods.item.detail"
        self.session = requests.Session()

    def build_hmac_sign(self, body: Dict, timestamp: str) -> str:
        """得力官方Header+报文联合HMAC-SHA256签名算法"""
        body_json = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
        # 官方固定签名拼接串
        sign_source = f"POST/v2/open{self.api_module}{self.api_cmd}{timestamp}{body_json}"
        sign_obj = hmac.new(self.app_secret.encode("utf-8"), sign_source.encode("utf-8"), hashlib.sha256)
        return sign_obj.hexdigest().lower()

    def get_goods_detail(self, item_code: str) -> Dict:
        """根据商品编码查询完整办公货源详情"""
        # 前置参数校验
        if len(str(item_code)) < 6:
            return {"code": -1, "msg": "商品编码长度不合法", "data": None}
        timestamp = str(int(time.time() * 1000))
        body_params = {"itemCode": item_code}
        sign = self.build_hmac_sign(body_params, timestamp)
        # 得力专属鉴权请求头
        headers = {
            "App-Key": self.app_key,
            "App-Timestamp": timestamp,
            "Api-Module": self.api_module,
            "Api-Cmd": self.api_cmd,
            "Sign": sign,
            "Content-Type": "application/json;charset=utf-8"
        }
        try:
            resp = self.session.post(self.base_url, headers=headers, json=body_params, timeout=15)
            raw_data = resp.json()
            # 限流429指数退避重试
            if raw_data.get("code") == 429:
                time.sleep(3)
                return self.get_goods_detail(item_code)
            if raw_data.get("code") != 0:
                return {"code": -1, "msg": raw_data.get("msg", "接口业务异常"), "data": None}
            item_data = raw_data.get("data", {})
            spec_list = []
            # 解析耗材多规格阶梯批发价
            for spec in item_data.get("specList", []):
                spec_list.append({
                    "spec_code": spec.get("specCode"),
                    "spec_name": spec.get("specName"),
                    "box_num": spec.get("boxNum"),
                    "stock": spec.get("stockNum"),
                    "step_price": spec.get("stepPriceList", [])
                })
            # 办公耗材标准化清洗
            detail_result = {
                "item_code": item_data.get("itemCode"),
                "title": item_data.get("itemName"),
                "category": item_data.get("categoryName"),
                "material": item_data.get("material", ""),
                "min_buy": item_data.get("minBuy"),
                "market_price": float(item_data.get("marketPrice", 0)),
                "retail_price": float(item_data.get("salePrice", 0)),
                "main_img": item_data.get("mainImage"),
                "detail_img": item_data.get("detailImageList", []),
                "is_government": bool(int(item_data.get("supportGovPurchase", 0))),
                "spec_info": spec_list,
                "update_time": item_data.get("updateTime")
            }
            time.sleep(1)
            return {"code": 200, "msg": "success", "data": detail_result}
        except Exception as e:
            return {"code": -2, "msg": f"网络请求异常:{str(e)}", "data": None}

# 调用示例
if __name__ == "__main__":
    client = DeliGoodsDetailClient(
        app_key="开发者后台申请App-Key",
        app_secret="开发者后台App-Secret密钥"
    )
    res = client.get_goods_detail(item_code="DL-8888")
    print(json.dumps(res, ensure_ascii=False, indent=2))

四、实战原创避坑要点


  1. 时间戳强制 13 位毫秒数值,秒级时间戳会直接判定签名不匹配,多数简易教程未做强制约束。

  2. 请求报文必须压缩无空格 JSON,格式化换行、空格会改变签名源字符串,鉴权永久失败。

  3. Api-Module、Api-Cmd 固定放入 Header 参与加密,遗漏任一头部字段都会校验不通过。

  4. supportGovPurchase 政企采购标签仅企业签约账号可返回,普通经销商应用无该字段数据。

  5. stepPriceList 阶梯批发价为集采核心数据,需循环存储用于企业批量报价,零售业务无需解析。

群贤毕至

访客