当前位置: 首页 > news >正文

Java 调用 1688 商品详情 API 接口完全指南(2026版)

一、接口概述与前置准备
1.1 接口定位
1688 商品详情 API 是阿里巴巴开放平台提供的核心数据接口,主要用于:
基础信息获取:商品 ID、标题、类目、品牌、起订量(MOQ)
价格体系查询:批发价、阶梯价、建议零售价、分销代发价
库存与 SKU:多规格组合、实时库存、SKU 对应价格
多媒体数据:主图 URL、详情图列表、商品描述 HTML
商家资质:供应商名称、诚信通等级、公司信息
1.2 接入前置条件
表格
步骤 操作 说明
1 注册开发者账号 访问 1688开放平台 完成企业实名认证(个人开发者权限受限)
2 创建应用 在控制台「应用管理」中创建应用,获取 App Key 和 App Secret
3 申请权限 申请 alibaba.product.get 或 1688.item_get 接口调用权限
4 获取 Access Token 通过 OAuth 2.0 授权流程获取(部分接口需要)
⚠️ 注意:1688 API 主要面向企业,个人开发者权限受限。建议提前准备好营业执照等企业资质材料。
二、核心技术要点
2.1 签名机制(MD5)
1688 API 采用 MD5 签名算法,这是接入最容易出错的地方。核心步骤如下:
Step 1:收集所有业务参数(不含 sign、file 二进制)
Step 2:按参数名 ASCII 升序 排序
Step 3:拼接成 key1value1key2value2... 格式(无 = 无 &)
Step 4:在字符串首尾各拼接一次 app_secret,进行 MD5 加密,结果转大写
示例:
plain
复制
app_key = 123456
app_secret = 7a3b9c8d...

排序后:app_key123456formatjsonitem_id610947572360methodalibaba.item.get...
待签名串 = APP_SECRET + 排序串 + APP_SECRET
sign = MD5(待签名串).toUpperCase()
2.2 认证流程
接口采用 OAuth 2.0 认证,调用流程:
使用 app_key 和 app_secret 获取 access_token
在业务接口请求中携带 access_token
access_token 有效期通常为 3600 秒,需实现缓存刷新机制
三、Java 完整实现代码
3.1 项目依赖(Maven)
xml
复制



org.apache.httpcomponents
httpclient
4.5.14



com.alibaba
fastjson
2.0.43



org.projectlombok
lombok
1.18.30
provided



org.slf4j
slf4j-api
2.0.9


3.2 签名工具类
java
复制
package com.example.ali1688;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

/**

  • 1688 API 签名工具类

  • 签名规则:

    1. 过滤空值参数和 sign 参数本身
    1. 按参数名 ASCII 升序排序
    1. 拼接成 key+value 字符串(无分隔符)
    1. 首尾拼接 app_secret,MD5 加密后转大写
      */
      public class Ali1688SignUtil {

    /**

    • 生成 MD5 签名(1688 官方算法)

    • @param params 请求参数(不含 sign)

    • @param appSecret 应用密钥

    • @return 大写 32 位 MD5 签名字符串
      */
      public static String generateSign(Map<String, String> params, String appSecret)
      throws NoSuchAlgorithmException {

      // Step 1: 移除空值和 sign 参数
      Map<String, String> filtered = new TreeMap<>();
      for (Map.Entry<String, String> entry : params.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
      if (value != null && !value.trim().isEmpty() && !"sign".equals(key)) {
      filtered.put(key, value);
      }
      }

      // Step 2: TreeMap 已按 key 升序排序,直接拼接
      StringBuilder sb = new StringBuilder();
      for (Map.Entry<String, String> entry : filtered.entrySet()) {
      sb.append(entry.getKey()).append(entry.getValue());
      }

      // Step 3: 首尾拼接 app_secret
      String toSign = appSecret + sb.toString() + appSecret;

      // Step 4: MD5 加密并转大写
      MessageDigest md = MessageDigest.getInstance("MD5");
      byte[] digest = md.digest(toSign.getBytes(StandardCharsets.UTF_8));

      StringBuilder hex = new StringBuilder();
      for (byte b : digest) {
      hex.append(String.format("%02X", b & 0xFF));
      }

      return hex.toString();
      }

    /**

    • 快速测试签名
      */
      public static void main(String[] args) throws Exception {
      Map<String, String> params = new java.util.HashMap<>();
      params.put("method", "alibaba.item.get");
      params.put("app_key", "YOUR_APP_KEY");
      params.put("timestamp", String.valueOf(System.currentTimeMillis()));
      params.put("format", "json");
      params.put("v", "2.0");
      params.put("sign_method", "md5");
      params.put("item_id", "610947572360");

      String sign = generateSign(params, "YOUR_APP_SECRET");
      System.out.println("sign = " + sign);
      }
      }
      3.3 Access Token 管理器
      java
      复制
      package com.example.ali1688;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**

  • Access Token 管理器

  • 负责获取和缓存 access_token,支持自动刷新
    */
    public class AccessTokenManager {

    private static final Logger log = LoggerFactory.getLogger(AccessTokenManager.class);

    private final String appKey;
    private final String appSecret;
    private String accessToken;
    private long expireTime; // 过期时间戳(毫秒)

    // Token 刷新提前量(提前 5 分钟刷新)
    private static final long REFRESH_AHEAD = 5 * 60 * 1000;

    public AccessTokenManager(String appKey, String appSecret) {
    this.appKey = appKey;
    this.appSecret = appSecret;
    }

    /**

    • 获取有效 Token(自动刷新)
      */
      public synchronized String getValidToken() throws Exception {
      if (accessToken != null && System.currentTimeMillis() < expireTime - REFRESH_AHEAD) {
      return accessToken;
      }
      return refreshToken();
      }

    /**

    • 刷新 Token
      */
      private String refreshToken() throws Exception {
      log.info("正在刷新 Access Token...");

      // 实际调用 1688 OAuth 接口获取 token
      // 此处为简化示例,实际需根据 1688 OAuth 文档实现
      // 接口地址:https://oauth.1688.com/token

      this.accessToken = "mock_token_" + System.currentTimeMillis();
      this.expireTime = System.currentTimeMillis() + 3600 * 1000;

      log.info("Access Token 刷新成功,有效期至: {}",
      new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(expireTime)));

      return accessToken;
      }
      }
      3.4 商品详情 API 客户端
      java
      复制
      package com.example.ali1688;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**

  • 1688 商品详情 API 客户端

  • 核心接口:

    • alibaba.product.get / alibaba.item.get
    • 1688.item_get
      */
      public class Item1688ApiClient {

    private static final Logger log = LoggerFactory.getLogger(Item1688ApiClient.class);

    private final String appKey;
    private final String appSecret;
    private final AccessTokenManager tokenManager;

    // 正式环境地址(根据实际接口调整)
    private static final String API_URL =
    "https://gw.open.1688.com/openapi/param2/1/com.alibaba.product/alibaba.product.get";

    public Item1688ApiClient(String appKey, String appSecret) {
    this.appKey = appKey;
    this.appSecret = appSecret;
    this.tokenManager = new AccessTokenManager(appKey, appSecret);
    }

    /**

    • 获取商品详情(全量字段)
    • @param offerId 1688 商品 ID
    • @return 商品详情 JSON 对象
      */
      public JSONObject getItemDetail(String offerId) throws Exception {
      return getItemDetail(offerId, null);
      }

    /**

    • 获取商品详情(指定字段,优化性能)

    • @param offerId 1688 商品 ID

    • @param fields 指定返回字段,如 "offerId,title,price,skuInfo"

    • @return 商品详情 JSON 对象
      */
      public JSONObject getItemDetail(String offerId, String fields) throws Exception {

      // 1. 组装公共参数
      Map<String, String> params = new HashMap<>();
      params.put("app_key", appKey);
      params.put("method", "com.alibaba.product.alibaba.product.get");
      params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
      params.put("format", "json");
      params.put("v", "2.0");
      params.put("sign_method", "md5");

      // 2. 组装业务参数
      params.put("productId", offerId);
      if (fields != null && !fields.isEmpty()) {
      params.put("fields", fields);
      }

      // 3. 生成签名
      String sign = Ali1688SignUtil.generateSign(params, appSecret);
      params.put("sign", sign);

      // 4. 发送 POST 请求
      String response = sendPostRequest(API_URL, params);

      // 5. 解析响应
      JSONObject result = JSON.parseObject(response);

      // 6. 错误处理
      if (result.containsKey("error_response")) {
      JSONObject error = result.getJSONObject("error_response");
      String errorCode = error.getString("code");
      String errorMsg = error.getString("msg");
      log.error("API 调用失败: {} (错误码: {})", errorMsg, errorCode);
      throw new RuntimeException("API调用失败: " + errorMsg + " (错误码: " + errorCode + ")");
      }

      // 7. 提取业务数据
      JSONObject productInfo = result.getJSONObject("productInfo");
      if (productInfo == null) {
      productInfo = result.getJSONObject("item_get_response");
      }

      log.info("成功获取商品详情, offerId: {}", offerId);
      return productInfo;
      }

    /**

    • 发送 HTTP POST 请求(表单格式)
      */
      private String sendPostRequest(String url, Map<String, String> params) throws IOException {
      CloseableHttpClient client = HttpClients.createDefault();
      HttpPost post = new HttpPost(url);

      // 构建表单参数
      StringBuilder formData = new StringBuilder();
      for (Map.Entry<String, String> entry : params.entrySet()) {
      if (formData.length() > 0) {
      formData.append("&");
      }
      formData.append(entry.getKey())
      .append("=")
      .append(URLEncoder.encode(entry.getValue(), "UTF-8"));
      }

      post.setEntity(new StringEntity(
      formData.toString(),
      "application/x-www-form-urlencoded",
      "UTF-8"
      ));

      log.debug("请求 URL: {}", url);
      log.debug("请求参数: {}", formData);

      try (CloseableHttpResponse response = client.execute(post)) {
      String result = EntityUtils.toString(response.getEntity(), "UTF-8");
      log.debug("响应结果: {}", result);
      return result;
      }
      }
      }
      3.5 商品详情数据模型
      java
      复制
      package com.example.ali1688.model;

import lombok.Data;
import java.math.BigDecimal;
import java.util.List;

/**

  • 1688 商品详情数据模型
    */
    @Data
    public class ItemDetail {

    // ========== 基础信息 ==========
    private String offerId; // 商品唯一 ID
    private String title; // 商品标题
    private String description; // 商品描述
    private String status; // 商品状态: published / off_sale
    private String categoryId; // 类目 ID
    private String brand; // 品牌

    // ========== 价格信息 ==========
    private BigDecimal price; // 当前批发价
    private BigDecimal retailPrice; // 建议零售价
    private List priceRanges; // 阶梯价格
    private Integer minOrderQuantity; // 最小起订量 (MOQ)
    private Integer maxOrderQuantity; // 最大订购量

    // ========== 库存信息 ==========
    private Integer stock; // 实时库存
    private List skuList; // SKU 列表

    // ========== 多媒体 ==========
    private String picUrl; // 主图 URL
    private List itemImgs; // 商品图集

    // ========== 供应商信息 ==========
    private SupplierInfo supplier; // 供应商信息

    // ========== 物流信息 ==========
    private LogisticsInfo logistics; // 物流信息

    @Data
    public static class PriceRange {
    private Integer startQuantity;
    private BigDecimal price;
    }

    @Data
    public static class SkuInfo {
    private String skuId;
    private String skuSpec;
    private BigDecimal skuPrice;
    private Integer skuStock;
    private List skuProperties;
    }

    @Data
    public static class SkuProperty {
    private String propName;
    private String value;
    }

    @Data
    public static class SupplierInfo {
    private String supplierName;
    private String supplierType;
    private String province;
    private String city;
    private String creditLevel;
    }

    @Data
    public static class LogisticsInfo {
    private BigDecimal freight;
    private String deliveryTime;
    private String unitWeight;
    private String packageSize;
    }
    }
    3.6 数据解析器
    java
    复制
    package com.example.ali1688;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.ali1688.model.ItemDetail;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**

  • 1688 商品详情数据解析器
    */
    @Slf4j
    public class ItemDetailParser {

    public static ItemDetail parse(JSONObject json) {
    ItemDetail item = new ItemDetail();

    try {
    // 基础信息
    item.setOfferId(json.getString("productId"));
    item.setTitle(json.getString("subject"));
    item.setDescription(json.getString("description"));
    item.setStatus(json.getString("status"));

    // 价格信息
    if (json.containsKey("priceRanges")) {
    JSONArray ranges = json.getJSONArray("priceRanges");
    List<ItemDetail.PriceRange> priceRanges = new ArrayList<>();
    for (int i = 0; i < ranges.size(); i++) {
    JSONObject range = ranges.getJSONObject(i);
    ItemDetail.PriceRange pr = new ItemDetail.PriceRange();
    pr.setStartQuantity(range.getInteger("startQuantity"));
    pr.setPrice(range.getBigDecimal("price"));
    priceRanges.add(pr);
    }
    item.setPriceRanges(priceRanges);
    if (!priceRanges.isEmpty()) {
    item.setPrice(priceRanges.get(0).getPrice());
    }
    }

    item.setMinOrderQuantity(json.getInteger("minOrderQuantity"));
    item.setMaxOrderQuantity(json.getInteger("maxOrderQuantity"));
    item.setStock(json.getInteger("amount"));

    // SKU 信息
    if (json.containsKey("skuInfos")) {
    JSONArray skus = json.getJSONArray("skuInfos");
    List<ItemDetail.SkuInfo> skuList = new ArrayList<>();
    for (int i = 0; i < skus.size(); i++) {
    JSONObject skuJson = skus.getJSONObject(i);
    ItemDetail.SkuInfo sku = new ItemDetail.SkuInfo();
    sku.setSkuId(skuJson.getString("skuId"));
    sku.setSkuPrice(skuJson.getBigDecimal("price"));
    sku.setSkuStock(skuJson.getInteger("amountOnSale"));

    if (skuJson.containsKey("attributes")) {
    JSONArray attrs = skuJson.getJSONArray("attributes");
    List<ItemDetail.SkuProperty> props = new ArrayList<>();
    StringBuilder specBuilder = new StringBuilder();

    for (int j = 0; j < attrs.size(); j++) {
    JSONObject attr = attrs.getJSONObject(j);
    ItemDetail.SkuProperty prop = new ItemDetail.SkuProperty();
    prop.setPropName(attr.getString("attributeName"));
    prop.setValue(attr.getString("attributeValue"));
    props.add(prop);

    if (specBuilder.length() > 0) specBuilder.append("-");
    specBuilder.append(attr.getString("attributeValue"));
    }
    sku.setSkuProperties(props);
    sku.setSkuSpec(specBuilder.toString());
    }
    skuList.add(sku);
    }
    item.setSkuList(skuList);
    }

    // 图片
    item.setPicUrl(json.getString("imageUrl"));

    // 供应商信息
    if (json.containsKey("supplier")) {
    JSONObject sup = json.getJSONObject("supplier");
    ItemDetail.SupplierInfo supplier = new ItemDetail.SupplierInfo();
    supplier.setSupplierName(sup.getString("companyName"));
    supplier.setProvince(sup.getString("province"));
    supplier.setCity(sup.getString("city"));
    item.setSupplier(supplier);
    }

    // 物流信息
    if (json.containsKey("shippingInfo")) {
    JSONObject ship = json.getJSONObject("shippingInfo");
    ItemDetail.LogisticsInfo logistics = new ItemDetail.LogisticsInfo();
    logistics.setUnitWeight(ship.getString("unitWeight"));
    logistics.setPackageSize(ship.getString("packageSize"));
    item.setLogistics(logistics);
    }

    } catch (Exception e) {
    log.error("解析商品详情失败: {}", e.getMessage(), e);
    }

    return item;
    }
    }
    3.7 使用示例
    java
    复制
    package com.example.ali1688;

import com.alibaba.fastjson.JSONObject;
import com.example.ali1688.model.ItemDetail;

public class Item1688Demo {

public static void main(String[] args) {
String appKey = "your_app_key_here";
String appSecret = "your_app_secret_here";
String offerId = "610947572360";

try {
Item1688ApiClient client = new Item1688ApiClient(appKey, appSecret);

// 指定返回字段(优化性能)
String fields = "productId,subject,priceRanges,imageUrl,skuInfos," +
"amount,minOrderQuantity,supplier,shippingInfo";

JSONObject response = client.getItemDetail(offerId, fields);
ItemDetail item = ItemDetailParser.parse(response);

System.out.println("========== 商品基础信息 ==========");
System.out.println("商品ID: " + item.getOfferId());
System.out.println("商品标题: " + item.getTitle());

System.out.println("\n========== 价格信息 ==========");
System.out.println("批发价: ¥" + item.getPrice());
System.out.println("起订量: " + item.getMinOrderQuantity() + " 件");

if (item.getPriceRanges() != null) {
System.out.println("阶梯价格:");
for (ItemDetail.PriceRange range : item.getPriceRanges()) {
System.out.println(" ≥" + range.getStartQuantity() + " 件: ¥" + range.getPrice());
}
}

System.out.println("\n========== 库存与 SKU ==========");
System.out.println("总库存: " + item.getStock());
if (item.getSkuList() != null) {
for (ItemDetail.SkuInfo sku : item.getSkuList()) {
System.out.println(" - " + sku.getSkuSpec() +
": ¥" + sku.getSkuPrice() + " (库存: " + sku.getSkuStock() + ")");
}
}

System.out.println("\n========== 供应商信息 ==========");
if (item.getSupplier() != null) {
System.out.println("供应商: " + item.getSupplier().getSupplierName());
System.out.println("所在地: " + item.getSupplier().getProvince());
}

} catch (Exception e) {
System.err.println("获取商品详情失败: " + e.getMessage());
e.printStackTrace();
}
}
}
四、关键字段映射表

字段名 说明 适用场景
productId / offerId 商品唯一标识 数据同步主键
subject 商品标题 展示、搜索
priceRanges 阶梯价格区间 B2B 批量采购定价
minOrderQuantity 最小起订量 (MOQ) 采购门槛判断
amount 实时可售库存 库存同步
skuInfos 规格组合信息 多 SKU 管理
imageUrl 主图 URL 图片展示
supplier.companyName 供应商名称 供应商筛选
shippingInfo.unitWeight 单位重量 物流计费
五、高频异常与排查

错误现象 常见原因 排查方案
Invalid Signature 时间戳单位错误、参数含空格、空值参入签名 时间戳必须是毫秒级;严格过滤空值
401/403 无权限 未申请接口权限、应用未审核、Token 过期 检查开放平台权限管理;实现 Token 自动刷新
429 限流 QPS 超过平台限制 增加请求间隔(建议 ≥1 秒);使用本地缓存
商品 ID 不存在 ID 错误、商品下架 确认商品状态;从商品链接中提取正确 ID
六、生产环境最佳实践
6.1 调用频率控制
官方限制:普通应用 QPS 为 1,企业应用 QPS 为 5
建议策略:批量调用时加入 Thread.sleep(1000) 控制速率;使用 Redis 缓存减少重复请求
6.2 异常重试机制
java
复制
public ItemDetail getItemDetailWithRetry(String offerId, int maxRetries) {
for (int i = 0; i < maxRetries; i++) {
try {
return getItemDetail(offerId);
} catch (Exception e) {
if (i == maxRetries - 1) throw e;
long sleepTime = (long) Math.pow(2, i) * 1000; // 指数退避
Thread.sleep(sleepTime);
}
}
return null;
}
6.3 异步处理(推荐)
对于大批量商品同步,建议使用 RabbitMQ/Kafka 消息队列削峰填谷,避免直接高并发调用 API。
6.4 数据安全
密钥管理:App Secret 严禁硬编码,使用配置中心或 KMS
HTTPS 强制:所有 API 调用必须使用 HTTPS
日志脱敏:禁止日志中输出 App Secret、Access Token
七、相关接口扩展
表格
接口名称 功能 配合场景
1688.item_search 关键词搜索商品列表 选品时先搜索再获取详情
1688.item_search_img 以图搜商品 找同款/竞品分析
alibaba.item.sku.get 单独获取 SKU 详情 精细化库存监控
seller_info 获取店铺/供应商详情 供应商资质评估
八、总结
📌 一句话总结:1688 签名 = 按参数名 ASCII 升序拼 key+value → 首尾加 AppSecret → MD5 → 大写,空值剔除、timestamp 用毫秒、sign 本身不参与签名。

如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。

http://www.zskr.cn/news/1530117.html

相关文章:

  • 什么眼油淡纹好用?3款淡纹必备眼油,舒缓眼周干纹细纹透亮眼周 - 全网最美
  • MSC8251 DMA控制器GCR_DREQ1寄存器配置详解与实战
  • 5大功能如何让Digital成为数字电路设计与仿真的首选工具?
  • MPC8533E PCIe错误处理实战:从寄存器机制到调试排查
  • 多维聚合数据操作:ROLLUP、CUBE与GROUPING SETS实战避坑指南
  • 义乌工商财税选哪家?荣伦财税:合规靠谱,创业更省心 - 资讯速览
  • AI 编译器优化技术:从计算图融合到算子自动调优的底层实践
  • 淄博黄金回收哪家靠谱?本地靠谱实体门店汇总测评 - 余生黄金回收
  • WCT1011B DAC模块解析:从5位基准到12位通用DAC的嵌入式应用
  • 2026去屑止痒洗发水实测:亲测 6 款,终于找到头屑克星 - 新闻快传
  • 项目之 头满分_2FastText
  • Platinum-MD:让MiniDisc重获新生的现代化音频传输方案
  • 别再把配置文件和数据放一起了!手把手教你分离KingbaseES V8的配置文件,运维效率翻倍
  • 如何快速获取全球地理数据:Geo-JSON数据集的终极应用指南
  • Nature Immunology | 肿瘤来源支链α-酮酸通过靶向Notch2重编程巨噬细胞介导肿瘤免疫逃逸
  • AI聊天隐私风险与三道物理隔离防护墙
  • 2026重庆天然翡翠回收,合扬实体老店更可信 - 奢侈品交易观察员
  • 魔兽世界字体合并补全工具:5分钟彻底告别游戏乱码
  • 如何在Windows电脑上免费实现AirPlay 2投屏接收:跨平台无线屏幕共享终极指南
  • Windows Defender完全控制:开源工具defender-control的技术深度解析
  • 如何让Windows掌机游戏体验媲美专业游戏主机:HandheldCompanion深度解析
  • 从‘False’到‘True’:手把手教你诊断并修复PyTorch CUDA不可用问题(Anaconda环境)
  • Tickets:基于Rust+Tauri+Vue的高效演唱会抢票智能解决方案
  • 2026 靠谱北京工商注册代办/公司注册代办公司推荐 实测数据全面解析 - 互联网科技品牌测评
  • 深入解析MPC8533E中断控制器:从架构原理到实战配置
  • 抖音批量下载工具完全指南:从单视频到用户主页的高效解决方案
  • 手把手教你搞定创维E900-S高安版刷机:从识别板号到当贝桌面完美运行
  • 告别命令行恐惧:用RedisInsight 2.0图形化搞定Redis监控与调试(附Docker一键部署)
  • 城通网盘解析工具:3分钟实现高速下载的完整指南
  • 【2026年6月】净化工程设计厂家优质企业推荐|净化工程设计,净化车间施工,净化车间安装优选|无锡一净净化设备有限公司 - 多才菠萝