图片展示

成 都 狮 龙 书 廊 科 技 有 限 责 任 公 司

Chengdu Shilong Pearson Education technology  Limited  Liability  Technology Group Co., Ltd.

头条号网站验证文件

好啊,"搜 "

 

 

 

 

 

 

 

好啊,"搜 "

 

 

 

客服电话:13904310313   

 

 

 

公司总机:028-67876373              

 

 

 

钉钉客服:17684321066                   

 

 

 

备案电话:15680712313 

 

 

 

商标注册服务电话:15210354365  

 

 

 

公安部备案号:22010602000144 

 

 

 

google-site-verification: googlea5d4809e7c237a00.html

 

 

 

 

 

 

 

SPI网关服务接入指南

狮龙书廊 青云科技

SPI网关服务接入指南

100

产品参数

  • 标准设计 1
  • 产品外观 1
  • 文本模块 1
  • 文件标准 1
展开全部 收起

产品详情

SPI网关服务接入指南

更新时间:2022-09-13 16:24:21访问次数:2950

一、查看场景和接口

对于ISV或者自研商家来说,只有官方同学添加相关场景的授权之后,开发者才可以在自己的控制台看到相关的场景及需要实现的接口及接口文档。

!

二、根据接口文档进行编码

2.1.接口实现大致流程

2.2.调用方式

GET/POST

2.3.通讯协议

HTTPS

2.4.验签(官方SDK已支持SPI验签-> 参考文档中心

为了防止API调用过程中被黑客恶意篡改,抖店开放平台在发起调用任何一个API都会携带签名。ISV服务端在接收到请求后需要对请求做验签,确保请求是来自抖店开放平台的而不是其他的非法请求。目前从抖店开放平台发出的请求均采用MD5进行加密。
说明:验签只是为了验证参数有没有被篡改,所以服务商在接收到抖店开放平台的请求后**一定要把验签放在第一步、一定要把验签放在第一步、一定要把验签放在第一步。**验签测试阶段,我们构造的测试参数并不一定完全符合业务逻辑,但是这不会影响验签。一定要拿着我们原始的请求去做签名计算,而不是先反序列化或者解析成你们自己定义的结构体后用你们自己的结构体去做签名计算,这样有可能导致签名失败。即便现在不失败,后面我们新增参数的话,你们的接口可能会出兼容问题。

获得sign的过程如下:(和API不一样哦)

1、将param_json中参数按照key字母先后顺序排序,组成json

  • 例如: param_json={"product_id":123,"code":"HHK"} 需要调整为param_json={"code":"HHK","product_id":"123"}
  • 特殊字符需要转义:"&"转成"\u0026";"<"转成"\u003c";">"转成"\u003e"
  • 使用gson的同学注意要进行disableHtmlEscaping
  • 使用python json.dumps的同学注意seperator不要让json字段间的逗号带空格

说明:如果是GET请求 param_json请从url中获取,如果是post请求,param_json的value为post请求的body
2、请求参数按照字母先后顺序排列

  • 将param_json,app_key,timestamp排序为app_key,param_json,timestamp 没有method和v哦 没有method和v哦 没有method和v哦

3、把参数名和参数值进行拼装

  • 例如:app_keyxxxparam_jsonxxxtimestampxxx

4、把app_secret分别拼接在上面得到的字符串的两端,假定app_secret的值为AppSecret

  • 例如:AppSecretXXXXAppSecret

5、上述步骤获得的待加密字符串,使用 MD5签名算法后得到sign,与请求中的sign进行比较,如果不一致则验签失败。
注:计算签名逻辑请使用下面的示例代码!!!不要自己实现

2.5.代码示例

SPISDK已经上线,推荐使用SDK对接,SDK说明文档:抖店开放平台SPI&消息网关SDK,使用SDK对接可跳过下面示例代码部分

Java示例代码

以接口“demo/spi”为例

public Object spiDemo() { 
DemoSpiRequest request =new DemoSpiRequest(); 
//param中的参数从服务端调用你们发布的地址上取 
//sign timestamp sign_method app_key sign_v2从URL参数取 
//paramJson分为两种情况,如果是get请求,从URL参数取,如果post请求从请求体里取 
//举个例子,发布的地址是http://www.abc.com 
//服务端实际调用时的请求地址是:http://www.abc.com?app_key=xxx&sign=xxx&sign_v2=xxx&sign_method=xxx×tamp=xxx¶m_json=xxx 
request.getParam().setSign( xxxx ); 
request.getParam().setTimestamp( xxxx ); 
request.getParam().setSignMethod( xxxx ); 
request.getParam().setAppKey( xxxx ); 
request.getParam().setParamJson( xxxx ); 
request.getParam().setSignV2( xxxx ); 
request.registerHandler(bizHandler); 
 
DemoSpiResponse response = request.execute(); 
//将response序列化成json返回 
return response; 
} 
 
private DoudianOpSpiBizHandler bizHandler = new DoudianOpSpiBizHandler() { 
@Override 
public void handle(DoudianOpSpiContext context) { 
 
// 获取入参对象 
DemoSpiParam param = context.getParam(); 
// 业务处理逻辑 
// ... 
// 设置data数据 
DemoSpiData data = context.getData(); 
// data.setXXX() 
// 返回成功 
context.wrapSuccess(); 
// 返回失败 
context.wrapError(100002L,系统错误 ); 
} 
};

Golang示例代码

import ( 
 "code.byted.org/middleware/hertz" 
 "crypto/md5" 
 "encoding/hex" 
 "encoding/json" 
 "io" 
 "sort" ) 
 
// TestSpi . // @router /api/spi/test [POST] func TestSpi(c *hertz.RequestContext) { 
 //1.从请求中解析入参 
 appKey := c.Query("app_key") 
 paramJson := c.Query("param_json") 
 timestamp := c.Query("timestamp") 
 sign := c.Query("sign") 
 
 //2.参数校验,此处省略 
 
 //3.验签 
 //3.1.解析业务参数 
 paramJsonInterfaceMap := make(map[string]interface{}) 
 err := json.Unmarshal([]byte(paramJson), ¶mJsonInterfaceMap) 
 if err != nil { 
c.JSON(200, &DemoResult{ 
 Code:100002, 
 Message: "参数解析失败", 
}) 
return 
 } 
 
 //3.2.把param_json的key按照自然顺序排序 
 mm := getJsonString(paramJsonInterfaceMap) 
 sortedParamJson, _ := json.Marshal(mm) 
 
 sortedString := "app_key" + appKey + "param_json" + string(sortedParamJson) + "timestamp" + timestamp 
 
 //3.3.拼接 appSecret 在头尾 
 appSecret := "63415a7a-de83-43ea-a522-cb616c47a4ef" 
 preSignString := appSecret + sortedString + appSecret 
 
 //3.4使用md5对参数加签 
 newSign := Md5(preSignString) 
 
 //3.5.将入参中的sign和加签后的结果作比较,如果不一致则验签失败。 
 if newSign != sign { 
c.JSON(200, &DemoResult{ 
 Code:100001, 
 Message: "验签失败", 
}) 
return 
 } 
 
 //4.业务处理,此处省略 
 
 //5.组装响应结果 
 c.JSON(200, &DemoResult{ 
Code:0, 
Message: "success", 
Data: &TestResult{ 
 Total: 100, 
 Test:false, 
 List: []*RefundOrder{ 
&RefundOrder{ 
 RefundId: "11111", 
 RefundReason: "七天无理由", 
}, 
 }, 
}, 
 }) 
} 
 
func Md5(s string) string { 
 h := md5.New() 
 _, _ = io.WriteString(h, s) 
 return hex.EncodeToString(h.Sum(nil)) 
} 
 
func getJsonString(param map[string]interface{}) interface{} { 
 sortedKeys := make([]string, 0) 
 for k := range param { 
sortedKeys = append(sortedKeys, k) 
 } 
 sort.Strings(sortedKeys) 
 
 sortedParamJsonMap := make(map[string]interface{}) 
 for _, sk := range sortedKeys { 
switch value := param[sk].(type) { 
case string: 
 sortedParamJsonMap[sk] = value 
case map[string]interface{}: 
 sortedParamJsonMap[sk] = getJsonString(value) 
case []interface{}: 
 if len(value) > 0 { 
if _, ok := value[0].(map[string]interface{}); ok { 
 var sliceResult = make([]interface{}, 0) 
 for _, interfaceValue := range value { 
switch mapInterfaceValue := interfaceValue.(type) { 
case map[string]interface{}: 
 sliceResult = append(sliceResult, getJsonString(mapInterfaceValue)) 
} 
 } 
 sortedParamJsonMap[sk] = sliceResult 
} else { 
 sortedParamJsonMap[sk] = value 
} 
 } else { 
sortedParamJsonMap[sk] = make([]interface{}, 0) 
 } 
default: 
 sortedParamJsonMap[sk] = value 
} 
 } 
 
 return sortedParamJsonMap 
} 
 
type DemoResult struct { 
 Codeint64 `json:"code"` 
 Message string`json:"message"` 
 Data*TestResult `json:"data"` 
} 
 
type TestResult struct { 
 Total int64`json:"total"` 
 Testbool `json:"test"` 
 List[]*RefundOrder `json:"list"` 
} 
 
type RefundOrder struct { 
 RefundId string `json:"refund_id"` 
 RefundReason string `json:"refund_reason"` 
} import ( 
 "code.byted.org/middleware/hertz" 
 "crypto/md5" 
 "encoding/hex" 
 "encoding/json" 
 "io" 
 "sort" ) 
 
// TestSpi . // @router /api/spi/test [POST] func TestSpi(c *hertz.RequestContext) { 
 //1.从请求中解析入参 
 appKey := c.Query("app_key") 
 paramJson := c.Query("param_json") 
 timestamp := c.Query("timestamp") 
 sign := c.Query("sign") 
 
 //2.参数校验,此处省略 
 
 //3.验签 
 //3.1.解析业务参数 
 paramJsonInterfaceMap := make(map[string]interface{}) 
 err := json.Unmarshal([]byte(paramJson), ¶mJsonInterfaceMap) 
 if err != nil { 
c.JSON(200, &DemoResult{ 
 Code:100002, 
 Message: "参数解析失败", 
}) 
return 
 } 
 
 //3.2.把param_json的key按照自然顺序排序 
 mm := getJsonString(paramJsonInterfaceMap) 
 sortedParamJson, _ := json.Marshal(mm) 
 
 sortedString := "app_key" + appKey + "param_json" + string(sortedParamJson) + "timestamp" + timestamp 
 
 //3.3.拼接 appSecret 在头尾 
 appSecret := "63415a7a-de83-43ea-a522-cb616c47a4ef" 
 preSignString := appSecret + sortedString + appSecret 
 
 //3.4使用md5对参数加签 
 newSign := Md5(preSignString) 
 
 //3.5.将入参中的sign和加签后的结果作比较,如果不一致则验签失败。 
 if newSign != sign { 
c.JSON(200, &DemoResult{ 
 Code:100001, 
 Message: "验签失败", 
}) 
return 
 } 
 
 //4.业务处理,此处省略 
 
 //5.组装响应结果 
 c.JSON(200, &DemoResult{ 
Code:0, 
Message: "success", 
Data: &TestResult{ 
 Total: 100, 
 Test:false, 
 List: []*RefundOrder{ 
&RefundOrder{ 
 RefundId: "11111", 
 RefundReason: "七天无理由", 
}, 
 }, 
}, 
 }) 
} 
 
func Md5(s string) string { 
 h := md5.New() 
 _, _ = io.WriteString(h, s) 
 return hex.EncodeToString(h.Sum(nil)) 
} 
 
func getJsonString(param map[string]interface{}) interface{} { 
 sortedKeys := make([]string, 0) 
 for k := range param { 
sortedKeys = append(sortedKeys, k) 
 } 
 sort.Strings(sortedKeys) 
 
 sortedParamJsonMap := make(map[string]interface{}) 
 for _, sk := range sortedKeys { 
switch value := param[sk].(type) { 
case string: 
 sortedParamJsonMap[sk] = value 
case map[string]interface{}: 
 sortedParamJsonMap[sk] = getJsonString(value) 
case []interface{}: 
 if len(value) > 0 { 
if _, ok := value[0].(map[string]interface{}); ok { 
 var sliceResult = make([]interface{}, 0) 
 for _, interfaceValue := range value { 
switch mapInterfaceValue := interfaceValue.(type) { 
case map[string]interface{}: 
 sliceResult = append(sliceResult, getJsonString(mapInterfaceValue)) 
} 
 } 
 sortedParamJsonMap[sk] = sliceResult 
} else { 
 sortedParamJsonMap[sk] = value 
} 
 } else { 
sortedParamJsonMap[sk] = make([]interface{}, 0) 
 } 
default: 
 sortedParamJsonMap[sk] = value 
} 
 } 
 
 return sortedParamJsonMap 
} 
 
type DemoResult struct { 
 Codeint64 `json:"code"` 
 Message string`json:"message"` 
 Data*TestResult `json:"data"` 
} 
 
type TestResult struct { 
 Total int64`json:"total"` 
 Testbool `json:"test"` 
 List[]*RefundOrder `json:"list"` 
} 
 
type RefundOrder struct { 
 RefundId string `json:"refund_id"` 
 RefundReason string `json:"refund_reason"` 
}

2.6.调用示例

127.0.0.1:6789/shop/user/register?app_key=6900812651828348424¶m_json=%7B%22order_id%22%3A%221234%22%2C%22page%22%3A10%2C%22size%22%3A11%7D&sign=6c4447b0bf1898d38f78ab80f7d86e46×tamp=2021-06-01+21%3A49%3A17

2.7.响应示例

2.7.1.成功响应示例

{ 
"code": 0, 
"message": "success", 
"data": { 
"total": 100, 
"test": false, 
"list": [ 
{ 
"refund_id": "11111", 
"refund_reason": "七天无理由" 
} 
]

2.7.2.失败响应示例

{ 
"code": 100001, 
"message": "验签失败", 
"data": null }

2.8.错误码

错误码说明
0业务处理成功
100001验签失败
100002参数错误
100003系统错误

更多业务错误码请参考各个SPI接口的接口文档说明。

三、接口自测

ISV在完成代码研发后,可以在抖店开发者控制台发起接口自测,自测通过之后可以将服务端url去发布。

四、服务端地址发布

接口自测通过后可以将服务端地址发布到对应的接口上。接口发布成功之后字节内部的业务就可以发起相关的调用啦。


五、修改服务端url

六、补充说明

为了方便排查问题,抖店开放平台在向服务商的地址发起请求时会把平台的logId放到请求的hedaer中,建议开发者在接受到请求后,除了打印请求入参外把logId也打印或者记录下来。


SPI网关服务接入指南
SPI网关服务接入指南
长按识别二维码查看详情
长按图片保存/分享
询盘

在线询盘 更多+
  • 联系人 *

  • 手机 *

  • 描述

  • 提交

  • 验证码
    看不清?换一张
    取消
    确定

咨询内容:


你还没有添加任何产品

加入成功
图片展示
图片展示

———

 

合作企业

“狮龙书廊,很多家企业合作的选择。〞

成都狮龙书廊科技有限公司于2016年12月08日成立。法定代表人毛凌国,公司经营范围包括:网络工程开发;计算机领域的技术开发、转让、咨询、推广服务;网页设计制作;

图片展示

———

 

伙伴合作企业

“商中在线,很多家企业的选择。〞

云指网络科技有限公司于2017年08月04日成立。法定代表人朱芹芹,公司经营范围包括:网络工程开发;计算机领域的技术开发、转让、咨询、推广服务;网页设计制作;

图片展示
文件标题
文件大小
下载次数
更新时间

成都狮龙书廊科技有限责任公司,是一家互联网高科技技术研究开发企业,本公司不以销售产品为目的,以展示公司文化为主。登记注册在四川成都高新区,企业纳税人识别号:91510100MA62N9D027,公司经营主业以计算机软件代码和硬件技术设计,电子产品和提供技术服务;软件开发;网页设计;图文设计;美术图案设计;网络技术服务;和商务咨询,代理制作发布各类广告推广业务,企业简称狮龙书廊科技,艺画斋----国际商业美术师,毛凌国.中国 互联网应用展示平台,是当代科技前沿领域开展艺术引领创新的云空间,在这里,本着帮助现有科技企业,开发设计领域,学术指导领域,新的创新,发明实用新型,和外观设计的展示平台,有机会聚集青年一代设计师,艺术设计者,学者和文化传承人的学术应用展示,普及传统美学思想与中外文化白花映演,实现中国梦,凝聚中国民族团结的社会价值。

狮龍畫廊---品牌是邦企科技认证的品牌项目,(狮龙书廊)企业实名认证的信用,科技驱动人文艺术和文明,推动中国文化传承事业在一带一路建设中的积极作用,我们不仅仅是企业,也是国际商业美术事业发展的推动者,高科技应用的转化和开发前沿领跑者,是未来职业发展的标准贯彻执行推广实体,是追求目标的技术型推广基石。成都狮龙书廊科技有限责任公司,服务社会的类型是以企业模式经营,独立的法人负责制体系,对社会组织和个体包括公司,开展各类的服务项目,如网络技术服务,建站设计,代理域名,空间结构分布云技术,微周微信开发和技术产品推广,特别是国际高科技人才服务和认证服务领域的经验的分享服务。成都狮龙书廊科技有限责任公司入围中国数字产业企业诚信企业,狮龙书廊通过中国电子人证服务产业联盟认证,具有较高服务和任用等级。艺画斋企业服务的一个项目。 

国际商业美术设计师(International Commercial Art Designer英文缩写ICAD)职业资格认证是国际商业美术设计师协会(International Commercial Art Designer Association,英文缩写ICADA)在全球范围内推行的四级商业美术设计专业资质认证体系的总称。它是以国际职业标准为导向,以实际工作能力、经验、知识和艺术素养为考评依据的一种新型的职业资格证书制度。  

 

 
CONTACT US

点击链接加入我的企业“成都狮龙廊科技有限责任公司长春分公司”,一起开启全新办公体验吧。 https://work.weixin.qq.com/join/w-A6Tt1b7iLuLRUM_ChDDg/hb_share_qymng_mjoin?is=203

 

电话总机:028-67873673

分机:

 

 

地址:成都高新区府城大道399号7栋2单元14层1404号

成都狮龙书廊科技有限责任公司 毛凌国 业务电话:17684321066神马搜索推广品牌竞价排名

<--------阿里地图开发代码-将代码嵌入到论坛、博客、网站中:------>

 

公共邮箱:public@maolg.com

企业管理员:admin@maolg.com

网站管理:webmaster@maolg.com

企业邮箱:mail.maolg.com

 

 

 

中国区官网:  www.maolg.com

成都总公司:   www.maolg.net

狮龙书廊长春分公司:www.maolg.cn

毛凌国我爱你: www.毛凌国.我爱你

 

添加微信好友,详细了解产品
使用企业微信
“扫一扫”加入群聊
复制成功
添加微信好友,详细了解产品
我知道了