淘宝、天猫对于h5的访问采用了和APP客户端不同的方式,由于在h5的js代码中保存appsercret具有较高的风险,mtop采用了随机分配令牌的方式,为每个访问端分配一个token,保存在用户的cookie中,通过cookie带回服务端分配的token, 客户端利用分配的token对请求的URL参数生成摘要值sign。
MTOP利用这个摘用值和cookie中的token来防止URL篡改。
当本地cookie中的token为空时(通常是第一次访问),mtop会收到”FAIL_SYS_TOKEN_EXOIRED:: 令牌过期“这个错误应答,同时mtop会生成token写入cookie中(response.cookies)。
第二次请求时,js通过读取cookie中的token值,按照约定的算法生成sign, sign在mtop的请求中带上,mtop通过cookie中和token用同样的方式计算出sign,与请求的sign进行比较,检查通过将返回api的应答,失败提示“FAIL_SYS_ILLEGAL_ACCESS:: 非法请求”
cookie中的token是有时效性的,遇到token失效时,将收到应答"FAIL_SYS_TOKEN_EXOIRED:: 令牌过期", 同时会写入新的token,js利用新的token重新计算sign并重发请求。
关于cookie中的token的自我检查,由于token在cookie中是明文的,可能会被仿冒,在输出的cookie中包含一个用非对称密钥的公钥加密后的token, MTOP在每次请求时会先检查cookie中的token是否是由服务端分配出去的(利用加密后的token和私钥还原token,与回传的明文token比较)
chrome打开淘宝网,按f12,全局搜索:sign,找到如下位置:
关于sign的生成公式:
let a=ck_token+ "&" + t + "&" + g + "&" + JSON.stringify(data);
let asign=sign(a);
例如:sign=51d9be5624c7179608223c8accc5ccbc
关于cookie的有效时长,cookie的有效时长为7天,但是token的有效时长目前为60分钟
_m_h5_tk: 格式为 明文token_expireTime, 从response.cookies处获取,如: 956ec8fa4134b1cf3ef4c6a2673274e9_1693194681803
token就是956ec8fa4134b1cf3ef4c6a2673274e9
很简单,即时间戳 int(time.time()*1000)
一般是固定数值,如:appKey=12574478
一般是提交的参数
let data={"id":id,"detail_v":"3.3.2","exParams":"{\"abbucket\":\"4\",\"id\":\""+id+"\",\"queryParams\":\"abbucket=4&id="+id+"\",\"domain\":\"https://detail.tmall.com\",\"path_name\":\"/item.htm\"}"};
let cookie=' _m_h5_tk=956ec8fa4134b1cf3ef4c6a2673274e9_1693194681803; _m_h5_tk_enc=6dd3bdf4559a75cacff0bb1877ee21f2; ';
const User_Agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36';
const fs = require("fs");
const https = require('node:https');
const http = require('node:http');
//---------------------------------------------------------------------------------------------------------------------------------------------------
function get_sku(id){
try{
//id=632225731831
let _m_h5_tk=getCookie("_m_h5_tk");
let ck_token=_m_h5_tk.split("_")[0]; //从cookie中提取token
let t=get_time(); //时间戳
let g='12574478'; //固定参数
let data={"id":id,"detail_v":"3.3.2","exParams":"{\"abbucket\":\"4\",\"id\":\""+id+"\",\"queryParams\":\"abbucket=4&id="+id+"\",\"domain\":\"https://detail.tmall.com\",\"path_name\":\"/item.htm\"}"}; //数据体,id为天猫商品id
let data_uri=encodeURIComponent(JSON.stringify(data));
console.log(data_uri);
let a=ck_token+ "&" + t + "&" + g + "&" + JSON.stringify(data); //签名参数
console.log(a);
let asign=sign(a); //签名
//https://h5api.m.tmall.com/h5/mtop.taobao.pcdetail.data.get/1.0/?jsv=2.6.1&appKey=12574478&t=1693013732683&sign=51d9be5624c7179608223c8accc5ccbc&api=mtop.taobao.pcdetail.data.get&v=1.0&isSec=0&ecode=0&timeout=10000&ttid=2022%40taobao_litepc_9.17.0&AntiFlood=true&AntiCreep=true&preventFallback=true&type=jsonp&dataType=jsonp&callback=mtopjsonp1&data=%7B%22id%22%3A%2220217382110%22%2C%22detail_v%22%3A%223.3.2%22%2C%22exParams%22%3A%22%7B%5C%22abbucket%5C%22%3A%5C%224%5C%22%2C%5C%22id%5C%22%3A%5C%2220217382110%5C%22%2C%5C%22rn%5C%22%3A%5C%2233937930c7499282aded6040bd5f87fb%5C%22%2C%5C%22spm%5C%22%3A%5C%22a1z10.3-b.w4011-3598985302.89.184d5361Crociz%5C%22%2C%5C%22queryParams%5C%22%3A%5C%22abbucket%3D4%26id%3D20217382110%26rn%3D33937930c7499282aded6040bd5f87fb%26spm%3Da1z10.3-b.w4011-3598985302.89.184d5361Crociz%5C%22%2C%5C%22domain%5C%22%3A%5C%22https%3A%2F%2Fdetail.tmall.com%5C%22%2C%5C%22path_name%5C%22%3A%5C%22%2Fitem.htm%5C%22%7D%22%7D
let api_url='https://h5api.m.tmall.com/h5/mtop.taobao.pcdetail.data.get/1.0/?jsv=2.6.1&appKey=12574478&t='+t+'&sign='+asign+'&api=mtop.taobao.pcdetail.data.get&v=1.0&isSec=0&ecode=0&timeout=10000&ttid=2022%40taobao_litepc_9.17.0&AntiFlood=true&AntiCreep=true&preventFallback=true&type=jsonp&dataType=jsonp&callback=mtopjsonp1&data='+data_uri;
console.log(api_url);
let real_url=api_url.replace('https://h5api.m.tmall.com','');
const options = {
hostname: 'h5api.m.tmall.com',
port: 443,
path: real_url,
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept':'*/*',
'Accept-Language':'zh-CN,zh;q=0.9',
'Referer': 'https://detail.tmall.com/',
'Sec-Ch-Ua':'"Chromium";v="116", "Not)A;Brand";v="24", "Google Chrome";v="116"',
'Sec-Ch-Ua-Mobile':'?0',
'Sec-Ch-Ua-Platform':'"Windows"',
'Sec-Fetch-Dest':'script',
'Sec-Fetch-Mode':'no-cors',
'Sec-Fetch-Site':'same-site',
'User-Agent': User_Agent,
'Cookie':cookie,
},
};
const req = https.request(api_url,options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
//console.log(res.headers);
res.setEncoding('utf8');
let body="";
res.on('data', (chunk) => {
body+=chunk;
});
res.on('end', () => {
console.log(body);
if(body.indexOf("令牌过期") != -1){ //令牌过期时,需重新更新cookie中的令牌,才能再次请求到数据。
set_cookie(res.headers); //获取新的令牌并更新cookie,技术支持:复制:byc6352
console.log("set_cookie");
get_sku(id); //再次发起数据请求
}
});
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
req.end();
}catch (e){
console.error(`problem with getfeeddata: ${e.message}`);
}
}
function get_time(){
let t=(new Date).getTime();
return t;
}