Datafocus HTTP源使用说明
简介
通用API源是一个支持用户编写javascript脚本,请求API数据并导入到Datafocus的API源功能。系统内置了ECMAScript5.1,允许用户使用javascript直接再Datafocus中请求外部API,而不需要额外自己实现API数据对接的服务。
通用API源功能不仅实现了基础的请求配置,让用户能够轻松接入各种API资源,更允许用户借助JavaScript脚本,执行更为复 杂、个性化的数据接入流程。通过灵活的配置与定制,用户能够实现对外部数据资源的精准获取与高效 利用。本指南将详细阐述该功能的使用方法,帮助用户快速上手并充分利用这一强大工具,以满足多样化的数据处理需求。
快速入门
本指南将会通过使用通用API功能创建一个简单的API源。通过这个教程,你将会从一个API中获取10快问快答的问题,并把数据保存到Datafocus。
基本要求
需要你已经会使用Datafocus的基础功能,包括页面操作,数据表操作等。
创建通用API
点击【数据表管理】-【外部数据源】-【HTTP数据源】-【新增】,创建通用API。
设置当前HTTP源的名称
在url地址栏中输入请求地址,https://opentdb.com/api.php?amount=10
点击**【测试请求】**可以测试当前接口并获取接口的返回数据。
点击**【保存】**,保存HTTP源后才可进入下一步配置。
点击**【下一步】**,列解析映射配置页面,在该页面用户需要完成从API接口数据到数据表列的映射。列数据通过与一段JSONPath绑定,实现列的映射。
注:主键是必填项,拥有相同主键的数据会被更新覆盖。
主键 | 列名 | 类型 | JSONPath |
---|---|---|---|
🔑 | 问题 | string | $.results[*].question |
难度 | string | $.results[*].difficulty | |
正确答案 | string | $.results[*].correct_answer | |
错误答案 | string | $.results[*].incorrect_answers | |
类型 | string | $.results[*].type | |
问题分类 | string | $.results[*].category |
点击**【导入】,输入源导入的表名,这里我们使用和HTTP源同样的名称,点击【确定】**。
此时可以看到新创建的表API_Question,但此时表还没有真正导入。点击**【配置】,点击【立即导入】**,等待表导入成功。
等待30秒左右后,点击**【预览数据】**,可以看到API数据被成功导入。
流程
HTTP源支持 ECMA5.1版本的JavaScript语法,允许用户灵活运用JS脚本,实现复杂的 API接入场景。
变量与上下文
整个HTTP源共用一个上下文,定义的变量所有配置想使用,只需要使用****双大括号框住变量,才调用请求时会将变量替换成变量值。如在url地址中输入变量:
在**【前置操作】、【后置操作】、【循环条件】中可以写入JavaScript脚本功能,三个脚本段共用上下文。建议在【前置操作】**中定义变量,在其他操作中只修改变量。
生命周期
当用户配置了JavaScript脚本后,在执行调用API请求时,Datafocus后台会为创建一个独立的JavaScript上下文环境,并按照前置操作、请求API、后置操作、循环条件的顺序依次执行,如果满足循环条件,将循环执行后三个环节(即请求API、执行后置操作、判断循环条件)。参考上图。
前置脚本
前置脚本将会在请求API前执行,用户可以在这里实现定义变量、初始化值、获取token等操作。前置脚本只会在开始时执行一次。
后置脚本
后置脚本将会在API请求结束后执行,用户可以通过内置变量responseData,获取到API返回的数据。用户可以在这里对数据进行二次加工处理。
循环条件
循环条件脚本需要用户实现一个loop函数,该函数的返回值将决定请求是否会循环调用,返回true是请求将会循环,返回false是将跳出循环。
测试请求
点击**【测试请求】**按钮,将会触发一次API请求,并检验前置脚本、后置脚本、循环条件、变量解析是否正确加载。响应结果将会显示在下方,内容包含上下文中的变量信息、发送请求的真实值、响应数据、控制台打印信息。
注:测试请求中,仅测试循环条件语法是否正确, 即使循环条件返回true,测试API请求时也仅会执行一次。在正式导入数据时,循环条件才会真正生效。
内置变量与函数
JavaScript中内置了一些功能函数和变量,帮助用户在请求API数据时实现一些必要的功能,如发送http 请求、使用哈希函数完成签名等。这些内置函数都在$对象下,调用方法如下:
// 对文本签名加密
var msg = "文本信息"
var key = "123456";
var sign = $.sha1(key, msg);
// 发送GET请求
$.get(url, function(data){console.log(data)});
// 发送POST请求
$.post(url, {
data: {nane: 'datafocus'},
success: function(data){ console.log(data) },
error: function(err) { console.log(err) }
})
内置变量与函数列表
函数/变量 | 说明 |
---|---|
$.get(url, data | callback:(data:object)=>{})) | get请求 |
$.post(url, data | callback:(data:object)=>{})) | post请求 |
$.encodeBase64(string) | base64编码, 返回字符串 |
$.decodeBase64(string) | base64解码, 返回字符串 |
$.md5(strOrBytes) | MD5函数,返回字符串 |
$.sha1(strOrBytes) | SHA1哈希函数,返回字符串 |
$.sha256(strOrBytes) | SHA256哈希函数,返回字符串 |
$.hmacSha1(key, msg) | HMAC-SHA1哈希加密函数,返回字符串 |
$.hmacSha256(key, msg) | HMAC-SHA256哈希加密函数,返回字符串 |
$.strToHex(text) | Hex字符串转HexBytes, 返回bytes |
$.hexToStr(bytes) | HexBytes转Hex字符串, 返回字符串 |
$.encodeStr(text, encoding='utf-8') | 字符串编码,默认utf-8, 返回bytes |
$.decodeStr(bytes, encoding='utf-8') | 字符串解码,默认utf-8, 返回字符串 |
$.getStorageValue() | 增量导入时,获取上次存储的记录值 |
$.setStorageValue(text) | 增量导入时,存储本次记录值 |
responseData | 存储API请求返回数据的变量 |
示例
JavaScript变量使用
在配置项中使用JavaScript定义的变量,并使用脚本动态赋值。
在【前置脚本】中定义一个变量pageNum,在Params参数中可以使用双大括号**来使用变量。在请求时,**会被解析为pageNum变量的实时值。
前置脚本
var pageNum=1;
循环请求
描述
遍历请求API数据时常见的使用场景,通过设置循环条件实现API请求的循环调用。
示例
在【前置脚本】中定义变量pageNum,用于指定请求的页数。并在【循环条件】中实现翻页和是否结束循环判断。
前置脚本
var pageNum=1;
循环条件
function loop(){
// loop condition here
pageNum++; // pageNum加1实现翻页
return responseData.values.length()!=0 // 如果还有数据,就继续循环调用,直到数据返回为空
}
在Params配置中绑定pageNum的值为pageNum变量。此时保存并导入表,正式导入表时API请求将会循环导入。
注:测试请求中,不会真实循环请求API,仅在正式导入数据时,循环条件才会真正生效。
数据预处理
描述
响应的数据可能并不能总是满足我们使用JSONPath映射到列的需求,如下方的天气数据。用户想抽取的数据为province,city,date,weather,但是province,city信息与date,weather信息并不在json对象的同一级,此时直接使用JSONPath去提取映射,会导致数据错位和丢失。此时我们需要对数据先进行处理,再对数据做映射。
{
"count": "1",
"infocode": "10000",
"status": "1",
"info": "OK",
"forecasts": [
{
"province": "浙江",
"city": "杭州市",
"adcode": "310000",
"reporttime": "2024-12-17 10:38:08",
"casts": [
{
"date": "2024-12-17",
"weather": "晴",
"wind": "西北",
"week": "2",
"power": "1-3",
"temp": "-1"
},
{
"date": "2024-12-18",
"weather": "晴",
"wind": "西",
"week": "3",
"power": "1-3",
"temp": "-5"
},
{
"date": "2024-12-19",
"dayweather": "晴",
"daywind": "西南",
"week": "4",
"power": "1-3",
"temp": "0"
}
]
}
]
}
示例
在【后置脚本】用户可以通过responseData变量获取到响应的json数据。
前置脚本
var forecasts=[];
后置脚本
// 循环遍历解析responseData数据,把分布在不同层的数据规整到一维数组中。
for (var i = 0; i < responseData.forecasts.length; i++) {
var city = responseData.forecasts[i];
for (var j = 0; j < city.casts.length; j++) {
var item = city.casts[j];
forecasts.push({
province: city.province,
city: city.city,
date: item.date,
dayweather: item.weather,
daywind: item.daywind
});
}
}
responseData = forecasts; // 将规整后的数据做为响应数据
处理后的响应数据
[
{
"province": "浙江",
"city": "杭州市",
"date": "2024-12-17",
"weather": "晴"
},
{
"province": "浙江",
"city": "杭州市",
"date": "2024-12-18",
"weather": "晴"
},
{
"province": "浙江",
"city": "杭州市",
"date": "2024-12-19",
"dayweather": "晴"
}
]
此时我们再使用JSONPath映射列,就不会出现映射错位或数据丢失的问题。
主键 | 列名 | 类型 | JSONPath |
---|---|---|---|
🔑 | 日期 | string | $[*].date |
🔑 | 省份 | string | $[*].province |
🔑 | 城市 | string | $[*].city |
天气 | string | $[*].weather |
数据签名与认证
描述
市面上绝大部分API都要求用户进行身份校验,HTTP源内置了常用的签名加密函数,供用户实现API的签名认证。
示例
在此示例中,用户需要根据第三方接口平台提供的appId和appKey,先获取token信息再请求API数据,且每次请求都需要对参数进行签名加密。
- AKSK常量定义;
- 获取第三方token认证;
- 请求第三方接口实现签名认证。
// 1.定义第三方接口请求认证信息
var appId = "0GEm********1XkH";
var appKey = "pLsv************************6Y2q";
var timestamp = parseInt((new Date()).valueOf()/1000);
var sign = appId+timestamp;
var token;
// 2.获取token
$.post("https://open.******.com/api/tokens",
{client_id: appId,
stamp: timestamp,
sign: $.sha1(appKey, sign)}, // 使用sha1完成签名
function(data){
token = data['Data']; // 获取返回的token
}
);
// 定义参数变量
var pIndex = 1;
var pSize = 100;
var total = 1;
// 3.实现获取数据接口签名
timestamp = (new Date()).valueOf();
var params = "_stamp="+timestamp+"&_token="+token+"&pindex="+pIndex+"&psize="+pSize;
var sign = $.sha1(appKey, params); // 使用sha1完成签名
增量导入
描述
API导入的速度与数据库直连导入的速度相差甚远,且考虑到API服务方的流量使用情况,在数据量大的情况下,增量导入是我们首先考虑的解决方案。
示例
以获取天气数据为例,每次增量导入数据时,用户都想基于上次导入时间节点,增量导入这段时间新增的天气数据。因此我们需要记录上次导入的时间信息,并传递参数给API,请求指定时间段内的数据。
用户可以使用内置**$.setStorageValue(value)方法存储45个字符以内的值,用于记录一次导入任务的截至点;使用内置$.getStorageValue()方法获取上次存储的截至信息。如果从未存储过信息,则获取到undefined**。
前置脚本
function formateDate(dt){
"""Date转日期字符串"""
var year = dt.getFullYear();
var month = ('0' + (dt.getMonth() + 1)).slice(-2);
var day = ('0' + dt.getDate()).slice(-2);
return year + '-' + month + '-' + day;
}
// 使用getStorageValue函数,获取上次的存储
var lastTime = $.getStorageValue();
if(lastTime == undefined){
lastTime = "2024-01-01";
}
//
var updateTime = formateDate(new Date());
配置参数
在参数中应用上次的存储的值用作增量更新的过滤条件
后置脚本
// 在后置脚本中,使用setStorageValue函数,存储本次增量更新时间节点
$.setStorageValue(updateTime);
增量导入配置
以上设置完HTTP源之后,还需要将表的导入方式设置为增量导入。全量导入在启动任务前会清空数据表,而增量导入则会保留数据,且只有开启了增量导入,setStorageValue的值才会真正被保存下来。
常见问题
循环条件没有生效
Q: 为什么测试请求的时候,结果没有循环调用?
A: 在测试请求中,仅会检测循环条件语法是否正确,并请求一次接口,而不会真的循环请求。只有正式导入数据时,循环条件才会真正生效。
为什么导入数据少了或只有部分数据
Q: 为什么导入的数据只有部分数据
A1: API导入表主键值唯一,当出现重复主键时,新导入的值会覆盖旧值。可以设置多主键并确保联合主键唯一,则不会出现值相互覆盖的情况。
A2: 数据在json的不同层级中,导致JSONPath解析出来的数据匹配不上。需要对数据处理后使数据层级一致后再使用JSONPath列映射。详见
为什么修改了联合主键,导入数据还是少了
Q: 修改HTTP源配置时,调整了主键,但是没有生效。
A: 修改主键后,表需要重建才能生效,需要在编辑后点击**【重新导入】**,才会使新的主键配置生效,且此时所有数据都将被置空,需要重新导入。