first commit
This commit is contained in:
commit
42c8cd3844
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
|
230
1.js
Normal file
230
1.js
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
const crypto = require('crypto');
|
||||||
|
const axios = require('axios');
|
||||||
|
const inquirer = require('inquirer');
|
||||||
|
// AES CBC 加密函数,返回 Base64
|
||||||
|
function aesEncrypt(plainText, key) {
|
||||||
|
const keyBuffer = Buffer.from(key, 'hex'); // 将16进制的密钥转换为 Buffer
|
||||||
|
const blockSize = 16; // AES 块大小
|
||||||
|
const iv = crypto.randomBytes(blockSize); // 生成随机 IV
|
||||||
|
|
||||||
|
// PKCS7 填充
|
||||||
|
function pkcs7Padding(text, blockSize) {
|
||||||
|
const padding = blockSize - (text.length % blockSize);
|
||||||
|
const padtext = Buffer.alloc(padding, padding);
|
||||||
|
return Buffer.concat([text, padtext]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cipher = crypto.createCipheriv('aes-128-cbc', keyBuffer, iv); // 创建加密器
|
||||||
|
cipher.setAutoPadding(true);
|
||||||
|
let encrypted = cipher.update(plainText);
|
||||||
|
encrypted = Buffer.concat([iv, encrypted, cipher.final()]); // 拼接 IV 和加密数据
|
||||||
|
return encrypted.toString('base64'); // 返回 Base64 编码的加密结果
|
||||||
|
}
|
||||||
|
// AES CBC 解密函数,返回解密后的明文
|
||||||
|
function aesDecrypt(encryptedText, key) {
|
||||||
|
const encryptedBuffer = Buffer.from(encryptedText, 'base64'); // 将Base64字符串转换为Buffer
|
||||||
|
const keyBuffer = Buffer.from(key, 'hex'); // 将16进制密钥转换为 Buffer
|
||||||
|
|
||||||
|
const blockSize = 16; // AES 块大小
|
||||||
|
const iv = encryptedBuffer.slice(0, blockSize); // 提取出IV
|
||||||
|
const encryptedData = encryptedBuffer.slice(blockSize); // 剩下的是加密数据
|
||||||
|
|
||||||
|
const decipher = crypto.createDecipheriv('aes-128-cbc', keyBuffer, iv); // 创建解密器
|
||||||
|
decipher.setAutoPadding(true);
|
||||||
|
|
||||||
|
let decrypted = decipher.update(encryptedData);
|
||||||
|
decrypted = Buffer.concat([decrypted, decipher.final()]); // 解密后的数据
|
||||||
|
return decrypted.toString(); // 返回解密后的明文字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟请求参数
|
||||||
|
const mockData = {
|
||||||
|
"FLXG3D56": {
|
||||||
|
mobile_no: "18276151590",
|
||||||
|
id_card: "45212220000827423X",
|
||||||
|
name: "张荣宏",
|
||||||
|
time_range: "5"
|
||||||
|
},
|
||||||
|
"FLXG54F5": {
|
||||||
|
mobile_no: "13812345678"
|
||||||
|
},
|
||||||
|
"FLXG162A": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"FLXG970F": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四"
|
||||||
|
},
|
||||||
|
"FLXG5876": {
|
||||||
|
mobile_no: "13812345678"
|
||||||
|
},
|
||||||
|
"FLXG9687": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "王五"
|
||||||
|
},
|
||||||
|
"FLXGC9D1": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "赵六"
|
||||||
|
},
|
||||||
|
"FLXGCA3D": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四"
|
||||||
|
},
|
||||||
|
"FLXGDEC7": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"IVYZ0B03": {},
|
||||||
|
"IVYZ385E": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"IVYZ5733": {
|
||||||
|
name: "李四",
|
||||||
|
id_card: "110101199003076534"
|
||||||
|
},
|
||||||
|
"IVYZ9363": {
|
||||||
|
man_name: "张三",
|
||||||
|
man_id_card: "110101199003076534",
|
||||||
|
woman_name: "王五",
|
||||||
|
woman_id_card: "110101199003076535"
|
||||||
|
},
|
||||||
|
"JRZQ0A03": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"JRZQ4AA8": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "王五"
|
||||||
|
},
|
||||||
|
"JRZQ8203": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "赵六"
|
||||||
|
},
|
||||||
|
"JRZQDBCE": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
bank_card: "6212261901001234567",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"QYGL2ACD": {
|
||||||
|
ent_name: "某企业",
|
||||||
|
legal_person: "李四",
|
||||||
|
ent_code: "91310000123456789X"
|
||||||
|
},
|
||||||
|
"QYGL6F2D": {
|
||||||
|
id_card: "110101199003076534"
|
||||||
|
},
|
||||||
|
"QYGL45BD": {
|
||||||
|
ent_name: "某公司",
|
||||||
|
legal_person: "王五",
|
||||||
|
ent_code: "91310000123456789X",
|
||||||
|
id_card: "110101199003076534"
|
||||||
|
},
|
||||||
|
"QYGL8261": {
|
||||||
|
ent_name: "某公司"
|
||||||
|
},
|
||||||
|
"QYGLB4C0": {
|
||||||
|
id_card: "110101199003076534"
|
||||||
|
},
|
||||||
|
"YYSY4B37": {
|
||||||
|
mobile_no: "13812345678"
|
||||||
|
},
|
||||||
|
"YYSY6F2E": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
mobile_type: "移动",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"YYSY09CD": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
mobile_type: "联通",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四"
|
||||||
|
},
|
||||||
|
"YYSYBE08": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
name: "张三"
|
||||||
|
},
|
||||||
|
"YYSYD50F": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534"
|
||||||
|
},
|
||||||
|
"YYSYF7DB": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
start_date: "2022-01-01"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const interfaceChoices = Object.keys(mockData);
|
||||||
|
|
||||||
|
// 选择接口和加密数据
|
||||||
|
async function requestAPI(interfaceName) {
|
||||||
|
const url = `http://api.tianyuanapi.com/api/v1/${interfaceName}`;
|
||||||
|
// const url = `http://127.0.0.1:10003/api/v1/${interfaceName}`;
|
||||||
|
|
||||||
|
const accessId = 'aa16cc6e9da90461';
|
||||||
|
const key = 'ff83609b2b24fc73196aac3d3dfb874f'; // AES 16进制密钥
|
||||||
|
|
||||||
|
// 模拟请求参数
|
||||||
|
const data = mockData[interfaceName];
|
||||||
|
if (!data) {
|
||||||
|
console.log(`接口 ${interfaceName} 的模拟数据未定义`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将数据转换为 JSON 并加密
|
||||||
|
const jsonStr = JSON.stringify(data);
|
||||||
|
console.log("jsonStr", jsonStr)
|
||||||
|
const encryptedData = aesEncrypt(jsonStr, key);
|
||||||
|
// 发送请求
|
||||||
|
try {
|
||||||
|
const response = await axios.post(url, {
|
||||||
|
data: encryptedData
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Access-Id': accessId,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(`接口 ${interfaceName} 返回:`, response.data);
|
||||||
|
const encryptedResponseData = response.data.data;
|
||||||
|
const decryptedData = aesDecrypt(encryptedResponseData, key);
|
||||||
|
// 解析解密后的字符串并结构化输出
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(decryptedData); // 将解密后的字符串转换为 JSON 对象
|
||||||
|
console.log(`接口 ${interfaceName} 返回解密后的数据:`);
|
||||||
|
console.log(JSON.stringify(jsonData, null, 2)); // 格式化输出,缩进为 2
|
||||||
|
} catch (parseError) {
|
||||||
|
console.error("解密后的数据无法解析为 JSON:", parseError);
|
||||||
|
console.log("解密后的数据:", decryptedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`请求接口 ${interfaceName} 失败:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 inquirer 进行接口选择
|
||||||
|
async function selectInterface() {
|
||||||
|
const answers = await inquirer.prompt([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'selectedInterface',
|
||||||
|
message: '请选择要请求的接口:',
|
||||||
|
choices: interfaceChoices
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const interfaceName = answers.selectedInterface;
|
||||||
|
await requestAPI(interfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行接口选择
|
||||||
|
selectInterface();
|
1394
package-lock.json
generated
Normal file
1394
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
package.json
Normal file
9
package.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.7",
|
||||||
|
"crypto": "^1.0.1",
|
||||||
|
"ejs": "^3.1.10",
|
||||||
|
"express": "^4.21.1",
|
||||||
|
"inquirer": "^8.2.6"
|
||||||
|
}
|
||||||
|
}
|
18
remark.txt
Normal file
18
remark.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
调用方未关联该服务
|
||||||
|
1、 FLXG54F5 - 易诉人群识别
|
||||||
|
2、 FLXG970F - 风险人员核验
|
||||||
|
3、FLXG5876 - 易诉人
|
||||||
|
4、QYGL45BD - 企业法人四要素核验
|
||||||
|
5、 YYSY4B37 - 手机在网时长
|
||||||
|
6、 YYSYBE08 - 运营商二要素核验(手机号、姓名)
|
||||||
|
7、 YYSYD50F - 运营商二要素核验(手机号、身份证)
|
||||||
|
8、YYSYF7DB - 手机二次卡
|
||||||
|
|
||||||
|
服务未启用
|
||||||
|
1、FLXGCA3D - 个人综合涉诉
|
||||||
|
2、FLXGDEC7 - 个人不良
|
||||||
|
3、 IVYZ385E - 自然人生存状态标识
|
||||||
|
4、 JRZQDCBE - 银行卡四要素验证
|
||||||
|
5、 QYGL6F2D - 人企关联
|
||||||
|
6、QYGL8261 - 企业综合涉诉
|
||||||
|
7、QYGLB4C0 - 股东人企关系精准版
|
249
server.js
Normal file
249
server.js
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const axios = require('axios');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = 3000;
|
||||||
|
|
||||||
|
// AES CBC 加密函数,返回 Base64
|
||||||
|
function aesEncrypt(plainText, key) {
|
||||||
|
const keyBuffer = Buffer.from(key, 'hex'); // 将16进制的密钥转换为 Buffer
|
||||||
|
const blockSize = 16; // AES 块大小
|
||||||
|
const iv = crypto.randomBytes(blockSize); // 生成随机 IV
|
||||||
|
const cipher = crypto.createCipheriv('aes-128-cbc', keyBuffer, iv);
|
||||||
|
cipher.setAutoPadding(true);
|
||||||
|
let encrypted = cipher.update(plainText);
|
||||||
|
encrypted = Buffer.concat([iv, encrypted, cipher.final()]);
|
||||||
|
return encrypted.toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
// AES CBC 解密函数,返回解密后的明文
|
||||||
|
function aesDecrypt(encryptedText, key) {
|
||||||
|
const encryptedBuffer = Buffer.from(encryptedText, 'base64');
|
||||||
|
const keyBuffer = Buffer.from(key, 'hex');
|
||||||
|
const blockSize = 16;
|
||||||
|
const iv = encryptedBuffer.slice(0, blockSize);
|
||||||
|
const encryptedData = encryptedBuffer.slice(blockSize);
|
||||||
|
const decipher = crypto.createDecipheriv('aes-128-cbc', keyBuffer, iv);
|
||||||
|
decipher.setAutoPadding(true);
|
||||||
|
let decrypted = decipher.update(encryptedData);
|
||||||
|
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||||
|
return decrypted.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟请求参数
|
||||||
|
const mockData = {
|
||||||
|
"FLXG3D56": {
|
||||||
|
mobile_no: "18276151590",
|
||||||
|
id_card: "45212220000827423X",
|
||||||
|
name: "张荣宏",
|
||||||
|
time_range: "5",
|
||||||
|
description: "特殊名单验证"
|
||||||
|
},
|
||||||
|
"FLXG54F5": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
description: "易诉人群识别"
|
||||||
|
},
|
||||||
|
"FLXG162A": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三",
|
||||||
|
description: "团伙欺诈排查(通用版)"
|
||||||
|
},
|
||||||
|
"FLXG970F": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四",
|
||||||
|
description: "风险人员核验"
|
||||||
|
},
|
||||||
|
"FLXG5876": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
description: "易诉人"
|
||||||
|
},
|
||||||
|
"FLXG9687": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "王五",
|
||||||
|
description: "电诈风险预警-标准版"
|
||||||
|
},
|
||||||
|
"FLXGC9D1": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "赵六",
|
||||||
|
description: "黑灰产等级"
|
||||||
|
},
|
||||||
|
"FLXGCA3D": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四",
|
||||||
|
description: "个人综合涉诉"
|
||||||
|
},
|
||||||
|
"FLXGDEC7": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三",
|
||||||
|
description: "个人不良"
|
||||||
|
},
|
||||||
|
"IVYZ385E": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三",
|
||||||
|
description: "自然人生存状态标识"
|
||||||
|
},
|
||||||
|
"IVYZ5733": {
|
||||||
|
name: "李四",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
description: "单人婚姻登记信息核验"
|
||||||
|
},
|
||||||
|
"IVYZ9363": {
|
||||||
|
man_name: "张三",
|
||||||
|
man_id_card: "110101199003076534",
|
||||||
|
woman_name: "王五",
|
||||||
|
woman_id_card: "110101199003076535",
|
||||||
|
description: "双人婚姻状态识别"
|
||||||
|
},
|
||||||
|
"JRZQ0A03": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三",
|
||||||
|
description: "借贷意向验证"
|
||||||
|
},
|
||||||
|
"JRZQ4AA8": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "王五",
|
||||||
|
description: "偿债压力指数"
|
||||||
|
},
|
||||||
|
"JRZQ8203": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "赵六",
|
||||||
|
description: "借贷行为验证"
|
||||||
|
},
|
||||||
|
"JRZQDCBE": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
bank_card: "6212261901001234567",
|
||||||
|
name: "张三",
|
||||||
|
description: "银行卡四要素验证"
|
||||||
|
},
|
||||||
|
"QYGL2ACD": {
|
||||||
|
ent_name: "某企业",
|
||||||
|
legal_person: "李四",
|
||||||
|
ent_code: "91310000123456789X",
|
||||||
|
description: "企业三要素核验"
|
||||||
|
},
|
||||||
|
"QYGL6F2D": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
description: "人企关联"
|
||||||
|
},
|
||||||
|
"QYGL45BD": {
|
||||||
|
ent_name: "某公司",
|
||||||
|
legal_person: "王五",
|
||||||
|
ent_code: "91310000123456789X",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
description: "企业法人四要素核验"
|
||||||
|
},
|
||||||
|
"QYGL8261": {
|
||||||
|
ent_name: "某公司",
|
||||||
|
description: "企业综合涉诉"
|
||||||
|
},
|
||||||
|
"QYGLB4C0": {
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
description: "股东人企关系精准版"
|
||||||
|
},
|
||||||
|
"YYSY4B37": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
description: "手机在网时长"
|
||||||
|
},
|
||||||
|
"YYSY6F2E": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
mobile_type: "CMCC",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "张三",
|
||||||
|
description: "运营商三要素核验(详版)"
|
||||||
|
},
|
||||||
|
"YYSY09CD": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
mobile_type: "CUCC",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
name: "李四",
|
||||||
|
description: "运营商三要素验证(简版)"
|
||||||
|
},
|
||||||
|
"YYSYBE08": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
name: "张三",
|
||||||
|
description: "运营商二要素核验(手机号、姓名)"
|
||||||
|
},
|
||||||
|
"YYSYD50F": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
id_card: "110101199003076534",
|
||||||
|
description: "运营商二要素核验(手机号、身份证)"
|
||||||
|
},
|
||||||
|
"YYSYF7DB": {
|
||||||
|
mobile_no: "13812345678",
|
||||||
|
start_date: "20220101",
|
||||||
|
description: "手机二次卡"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 使用 EJS 模板引擎
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
app.set('views', path.join(__dirname, 'views'));
|
||||||
|
|
||||||
|
// 解析POST请求的数据
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// 提供静态文件(比如 CSS)
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
|
// 提供前端页面
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.render('index', { interfaces: Object.keys(mockData), mockData: mockData });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理 API 请求
|
||||||
|
app.post('/request-api', async (req, res) => {
|
||||||
|
const { interfaceName, params } = req.body;
|
||||||
|
|
||||||
|
const url = `http://api.tianyuanapi.com/api/v1/${interfaceName}`;
|
||||||
|
const accessId = 'aa16cc6e9da90461';
|
||||||
|
const key = 'ff83609b2b24fc73196aac3d3dfb874f'; // AES 16进制密钥
|
||||||
|
|
||||||
|
const data = JSON.parse(params); // 使用用户自定义的参数
|
||||||
|
const jsonStr = JSON.stringify(data);
|
||||||
|
const encryptedData = aesEncrypt(jsonStr, key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post(url, { data: encryptedData }, {
|
||||||
|
headers: {
|
||||||
|
'Access-Id': accessId,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(" response.data", response.data)
|
||||||
|
// 如果 response.data.code 不等于 0,认为请求失败
|
||||||
|
if (response.data.code !== 0) {
|
||||||
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
message: `请求失败,错误代码: ${response.data.code}`,
|
||||||
|
error: response.data.message || '未知错误'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果 code 等于 0,继续解密
|
||||||
|
const encryptedResponseData = response.data.data;
|
||||||
|
const decryptedData = aesDecrypt(encryptedResponseData, key);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
encryptedResponse: response.data,
|
||||||
|
decryptedResponse: JSON.parse(decryptedData)
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
res.json({ success: false, message: '请求失败', error: error.message });
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
|
});
|
198
views/index.ejs
Normal file
198
views/index.ejs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>API 请求测试</title>
|
||||||
|
<style>
|
||||||
|
/* 页面整体布局,左右分栏 */
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧接口选择和输入框 */
|
||||||
|
.left-panel {
|
||||||
|
width: 35%;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 右侧响应显示框 */
|
||||||
|
.right-panel {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 布局样式 */
|
||||||
|
.radio-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px; /* 控制每个radio的间距 */
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-item {
|
||||||
|
flex: 1 0 20%; /* 每个radio占30%的宽度 */
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 控制radio按钮的对齐 */
|
||||||
|
.radio-item input {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框样式 */
|
||||||
|
textarea {
|
||||||
|
margin-top: 20px;
|
||||||
|
width: 100%;
|
||||||
|
height: 150px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式 */
|
||||||
|
button {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应结果样式 */
|
||||||
|
#result {
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading 样式 */
|
||||||
|
.loading {
|
||||||
|
display: none;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #007bff;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>选择API并发送请求</h1>
|
||||||
|
<div class="container">
|
||||||
|
<!-- 左侧接口选择 -->
|
||||||
|
<div class="left-panel">
|
||||||
|
<form id="apiForm">
|
||||||
|
<div id="radioGroup" class="radio-container">
|
||||||
|
<% interfaces.forEach(function(interface) { %>
|
||||||
|
<label class="radio-item">
|
||||||
|
<input type="radio" name="interface" value="<%=
|
||||||
|
interface %>" <%= interface === interfaces[0] ?
|
||||||
|
'checked' : '' %> >
|
||||||
|
<strong><%= interface %></strong> - <%=
|
||||||
|
mockData[interface].description || '无描述' %>
|
||||||
|
</label>
|
||||||
|
<% }); %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<textarea id="params" name="params" rows="10" cols="50">
|
||||||
|
</textarea>
|
||||||
|
<br />
|
||||||
|
<button type="submit" id="submitButton">发送请求</button>
|
||||||
|
|
||||||
|
<!-- Loading Text -->
|
||||||
|
<div class="loading" id="loadingText">
|
||||||
|
加载中,请稍候...
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧响应显示框 -->
|
||||||
|
<div class="right-panel">
|
||||||
|
<div id="result">响应结果将在此处显示</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 使用 <%- JSON.stringify(mockData) %> 安全地将 JSON 数据插入到 JavaScript 中
|
||||||
|
const mockData = <%- JSON.stringify(mockData) %>;
|
||||||
|
|
||||||
|
document.querySelectorAll('input[name="interface"]').forEach(function (radio) {
|
||||||
|
radio.addEventListener('change', function () {
|
||||||
|
const selectedInterface = this.value;
|
||||||
|
// 动态填充默认的模拟数据
|
||||||
|
const defaultParams = JSON.stringify(mockData[selectedInterface], null, 2);
|
||||||
|
document.getElementById('params').value = defaultParams;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('apiForm').addEventListener('submit', async function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// 获取相关元素
|
||||||
|
const interfaceName = document.querySelector('input[name="interface"]:checked').value;
|
||||||
|
const params = document.getElementById('params').value;
|
||||||
|
const submitButton = document.getElementById('submitButton');
|
||||||
|
const loadingText = document.getElementById('loadingText');
|
||||||
|
const resultDiv = document.getElementById('result');
|
||||||
|
|
||||||
|
// 禁用按钮并显示加载文本
|
||||||
|
submitButton.disabled = true;
|
||||||
|
loadingText.style.display = 'block';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/request-api', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ interfaceName, params })
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
resultDiv.innerHTML = `
|
||||||
|
<h2>请求结果:</h2>
|
||||||
|
<pre>加密返回: ${JSON.stringify(result.encryptedResponse, null, 2)}</pre>
|
||||||
|
<pre>解密返回: ${JSON.stringify(result.decryptedResponse, null, 2)}</pre>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
resultDiv.innerHTML = `
|
||||||
|
<h2>请求失败:</h2>
|
||||||
|
<p>${result.message}</p>
|
||||||
|
<p>${result.error}</p>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
resultDiv.innerText = '请求失败: ' + error;
|
||||||
|
} finally {
|
||||||
|
// 请求完成,恢复按钮并隐藏加载文本
|
||||||
|
submitButton.disabled = false;
|
||||||
|
loadingText.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化时,自动填充第一个接口的默认参数
|
||||||
|
document.querySelector('input[name="interface"]:checked').dispatchEvent(new Event('change'));
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user