企业对接Walmart平台API流程(一)

对接方案

  • Walmart API授权采用基于OAuth Token 的授权模式,并不是OAuth2.0的授权模式;
  • 这种授权模式是使用凭证授权的方式,需要卖家在 Walmart开发者后台生成一套凭证,凭证信息包括了Client ID 和 Client Secret。

一、US站点

如果是US站点,就需要在开发者后台获取以下信息。
在这里插入图片描述

请求头参数

在这里插入图片描述

  • WM_SVC.NAME Walmart Service Name 必填 例如:Walmart Marketplace
  • WM_QOS.CORRELATION_ID 每个请求的唯一Id 必填 例如: UUID
  • Authorization 用Client ID and Client Secret组合生成的Base64 encodes 必填 例如:Basic YzcyOTFjNmItNzI5MC0
  • WM_CONSUMER.CHANNEL.TYPE 如果凭证是卖家自己用的,这个值为空。如果是第三方服务商调用API,这个值需要第三方服务商从Walmart那里通过商务合作获得,这个参数是用于Walmart识别是哪个第三方在调用API的
  • WM_SEC.ACCESS_TOKEN 必填,通过用Client ID and Client Secret 请求Token API 获取的access_token,有效期为15分钟
1.获取授权
    /**
     * 对密钥进行编码
     *
     * @return
     */
    private String getAuthorization(String clientSecret, String clientId) {
        String str = clientSecret+ ":" + clientId;
        return "Basic " + Base64.encodeBase64String(str.getBytes());
    }
2.获取 US站点的token
**
     * 获取美国店铺的token
     *
     * @return
     */
    public String getUSAAccessToken(String authorization, ShopSettings shopSettings) {

		//先从redis中获取
        String redisKey = String.format(WalmartConstant.ACCESS_TOKEN, shopSettings.getAccountName());
        String accessToken = redisCache.getCacheObject(redisKey);
        if (StringUtils.isNotEmpty(accessToken)) {
            log.debug("从redis中获取token:{}", accessToken);
            return accessToken;
        }
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", authorization);
        headers.put("WM_SVC.NAME", shopSettings.getAccountName());
        headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString());

        try {
            HttpResponse response = HttpRequest.post(WalmartConstant.USA_TOKEN_URL)
                    .addHeaders(headers)
                    .body("grant_type=client_credentials", "application/x-www-form-urlencoded")
                    .execute();
            JSONObject jsonObject = JSONObject.parseObject(response.body());
            accessToken = jsonObject.getString("access_token");
            if (accessToken == null) {
                throw new CustomException("获取沃尔玛接口调用凭证失败", 500);
            }
        }catch (Exception e){
            log.error("【获取美国站点token值异常】,{}",e.getMessage());
            return null;
        }

        redisCache.setCacheObject(redisKey, accessToken, 899, TimeUnit.SECONDS);
        log.debug("生成的token为:{}", accessToken);

        return accessToken;
    }
3.获取访问US站点API的请求头
    /**
     * 获取访问Us站点API的请求头
     *
     * @return
     */
    public Map<String, String> getUsHeaders(Long accountId) {
        ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart");

        String authorization = getAuthorization(shopSettings.getClientSecret(), shopSettings.getClientId());

        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", authorization);
        headers.put("WM_SVC.NAME", shopSettings.getAccountName());
        headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString());
        headers.put("WM_SEC.ACCESS_TOKEN", getUSAccessToken(authorization, shopSettings));
        return headers;
    }
4.调用API测试
 /**
     * 获取节点上商品的库存
     * @param sku
     * @return
     */
    @GetMapping("/inventories/{sku}")
    public AjaxResult getInventory(@PathVariable(value = "sku") String sku,
                                   @RequestParam(required = false, value = "shipNode")String shipNode){
        if (StringUtils.isBlank(sku)){
            return AjaxResult.error(BaseError.CHECK_ERROR);
        }
        String url = "https://marketplace.walmartapis.com/v3/inventories/"+ sku;
        if (StringUtils.isNotBlank(shipNode)){
            url = url+"?shipNode=" + shipNode;
        }
        Map<String, String> headers = walmartUtil.getUsHeaders(60L);

		//执行请求,获取数据
        HttpResponse response = HttpRequest.get(url)
                .addHeaders(headers)
                .contentType("application/json")//一定要加这一行代码,否则可能会报错
                .execute();
        if (200 == response.getStatus()) {
            return AjaxResult.success(JSONObject.parseObject(response.body()));
        }
        return AjaxResult.error();
    }
二、CA站点

CA站点和US站点稍有不同,CA站点是在卖家中心的General Settings那里点击API跳转到页面去获取Consumer ID、Channel Type、Private Key。Consumer ID等同于US站点的Client ID,Private Key等同于Client Secret。Channel Type就是请求头参数中的WM_CONSUMER.CHANNEL.TYPE
在这里插入图片描述
在这里插入图片描述

1.获取CA站点的API的数字签名和时间戳
    /**
     * 获取访问加拿大店铺API的数字签名和时间戳参数
     *
     * @param requestUrl
     * @param requestMethod
     * @return
     */
    public Map<String, String> getSignatureAndTimestamp(String requestUrl, String requestMethod, Long accountId) {
        if (StringUtils.isEmpty(requestMethod) || StringUtils.isEmpty(requestUrl)) {
            throw new CustomException(BaseError.CHECK_ERROR);
        }
        Map<String, String> result = new HashMap<>();
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature = getWalmartAuthSignature(requestUrl, requestMethod, timestamp, accountId);
        result.put("authSignature", signature);
        result.put("timestamp", timestamp);
        return result;
    }


 /**
     * 获取沃尔玛认证数字签名
     *
     * @param requestUrl    要调用的完整 URL,包括路径和查询参数
     * @param requestMethod GET  or  POST
     * @param timestamp     时间戳
     * @return
     */
    private String getWalmartAuthSignature(String requestUrl, String requestMethod, String timestamp, Long accountId) {
        ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart");

        //登录后从开发者中心获取的Consumer ID
        String consumerId = shopSettings.getConsumerId();
        //私钥
        String privateKey = shopSettings.getPrivateKey();
        String stringToSign = consumerId + "\n" + requestUrl + "\n" + requestMethod + "\n" + timestamp + "\n";
        return signData(stringToSign, privateKey);
    }

/**
     * 签名算法
     *
     * @param stringToBeSigned  签名结构  消费者ID(Consumer ID) + "\n" + 完整路径(url) + "\n" + 时间戳(timestamp) + "\n";
     * @param encodedPrivateKey 私密秘钥Private Key
     * @return
     */
    private static String signData(String stringToBeSigned, String encodedPrivateKey) {
        String signatureString = null;

        try {
            byte[] encodedKeyBytes = Base64.decodeBase64(encodedPrivateKey);
            PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(encodedKeyBytes);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            PrivateKey myPrivateKey = kf.generatePrivate(privSpec);
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(myPrivateKey);
            byte[] data = stringToBeSigned.getBytes("UTF-8");
            signature.update(data);
            byte[] signedBytes = signature.sign();
            signatureString = Base64.encodeBase64String(signedBytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return signatureString;
    }
2.获取访问CA站点API的请求头
    /**
     * 获取访问CA站点API的请求头
     *
     * @return
     */
    public Map<String, String> getCaHeaders(String requestUrl, String requestMethod, Long accountId) {
        ShopSettings shopSettings = shopSettingsService.getShopSettingCache(accountId, "walmart");

        Map<String, String> map = getSignatureAndTimestamp(requestUrl, requestMethod, accountId);
        String authSignature = map.get("authSignature");
        String timestamp = map.get("timestamp");
        log.debug(authSignature);
        log.debug(timestamp);
        Map<String, String> headers = new HashMap<>();
        headers.put("WM_CONSUMER.CHANNEL.TYPE", shopSettings.getChannelType());
        headers.put("WM_SVC.NAME", shopSettings.getAccountName());
        headers.put("WM_QOS.CORRELATION_ID", UUID.randomUUID().toString());
        headers.put("WM_SEC.TIMESTAMP", timestamp);
        headers.put("WM_SEC.AUTH_SIGNATURE", authSignature);
        headers.put("WM_CONSUMER.ID", shopSettings.getConsumerId());
        return headers;
    }
3.调用API测试
public JSONObject listItemsCa(ItemParams itemParams, Long accountId) {
        String nextCursor = Optional.ofNullable(itemParams.getNextCursor()).orElse("*");
        String limit = Optional.ofNullable(itemParams.getLimit()).orElse("50");
        String url = "https://marketplace.walmartapis.com/v3/ca/items?nextCursor=" + nextCursor + "&limit=" + limit;

        Map<String, String> headers = walmartUtil.getCaHeaders(url, "GET", accountId);

        try {
            HttpResponse response = HttpRequest.get(url)
                    .addHeaders(headers)
                    .execute();
            if (200 == response.getStatus()){
                return JSONObject.parseObject(response.body());
            }
        }catch (Exception e){
            log.error("【walmart CA 查询商品错误】:{}", e.getMessage());
        }

        return new JSONObject();
    }

更新:2023年6月15日

如果在调CA站点的API时可能会出现下面这种几种情况,

  • WM_CONSUMER.CHANNEL.TYPE填错后的异常
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:errors xmlns:ns2="http://walmart.com/">
    <ns2:error>
        <ns2:code>INVALID_REQUEST_HEADER.GMP_GATEWAY_API</ns2:code>
        <ns2:field>WM_CONSUMER.CHANNEL.TYPE</ns2:field>
        <ns2:description>WM_CONSUMER.CHANNEL.TYPE set null or invalid</ns2:description>
        <ns2:info>One or more request headers are invalid.</ns2:info>
        <ns2:severity>ERROR</ns2:severity>
        <ns2:category>DATA</ns2:category>
        <ns2:causes/>
        <ns2:errorIdentifiers/>
    </ns2:error>
</ns2:errors>
  • WM_CONSUMER.ID填错后的异常
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:errors xmlns:ns2="http://walmart.com/">
    <ns2:error>
        <ns2:code>UNAUTHORIZED.GMP_GATEWAY_API</ns2:code>
        <ns2:field>UNAUTHORIZED</ns2:field>
        <ns2:description>Unauthorized</ns2:description>
        <ns2:info>Unauthorized token or incorrect authorization header. Please verify correct format: "Authorization: Basic Base64Encode(clientId:clientSecret)" For more information, see https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication.</ns2:info>
        <ns2:severity>ERROR</ns2:severity>
        <ns2:category>DATA</ns2:category>
        <ns2:causes/>
        <ns2:errorIdentifiers/>
    </ns2:error>
</ns2:errors>
- privateKey填错后的异常
```java
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:errors xmlns:ns2="http://walmart.com/">
    <ns2:error>
        <ns2:code>UNAUTHORIZED.GMP_GATEWAY_API</ns2:code>
        <ns2:field>UNAUTHORIZED</ns2:field>
        <ns2:description>Unauthorized</ns2:description>
        <ns2:info>Unauthorized token or incorrect authorization header. Please verify correct format: "Authorization: Basic Base64Encode(clientId:clientSecret)" For more information, see https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication.</ns2:info>
        <ns2:severity>ERROR</ns2:severity>
        <ns2:category>DATA</ns2:category>
        <ns2:causes/>
        <ns2:errorIdentifiers/>
    </ns2:error>
</ns2:errors>
  • timestamp填错后的异常【检查代码运行机器的系统时间是否和正常时间有偏差】
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:errors xmlns:ns2="http://walmart.com/">
    <ns2:error>
        <ns2:code>UNAUTHORIZED.GMP_GATEWAY_API</ns2:code>
        <ns2:field>UNAUTHORIZED</ns2:field>
        <ns2:description>Unauthorized</ns2:description>
        <ns2:info>Unauthorized token or incorrect authorization header. Please verify correct format: "Authorization: Basic Base64Encode(clientId:clientSecret)" For more information, see https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication.</ns2:info>
        <ns2:severity>ERROR</ns2:severity>
        <ns2:category>DATA</ns2:category>
        <ns2:causes/>
        <ns2:errorIdentifiers/>
    </ns2:error>
</ns2:errors>
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值