代理服务API
安全的外部API集成解决方案,支持跨域请求和敏感信息保护。
代理服务API(kinlink.proxy)提供了一个安全可靠的方式来调用外部系统的API,通过服务端代理机制解决跨域限制,同时保护敏感的认证信息(如Token、API Key)不被前端暴露。该API特别适用于需要与第三方系统集成的表单应用场景。
核心功能特性
代理服务的主要能力和优势
代理服务为表单应用提供了强大的外部集成能力,具备以下核心特性:
安全性保障
- Token隐藏:敏感认证信息仅在服务端配置,前端无法获取
- 跨域解决:绕过浏览器CORS限制,安全访问任何外部API
- 请求验证:服务端验证和过滤所有外部请求
集成便利性
- 统一接口:简单的API调用方式,支持所有HTTP方法
- 自动认证:服务端自动添加配置的认证头信息
- 错误处理:完整的异常处理和错误反馈机制
基础用法
代理API的调用方式和参数说明
API方法签名
kinlink.proxy(url, method, headers, body)快速上手示例
GET请求示例
// 简单的GET请求
const userData = await kinlink.proxy(
'https://api.example.com/users/123',
'GET',
{ 'Accept': 'application/json' }
);
console.log('用户信息:', userData);
// 带查询参数的GET请求
const searchResults = await kinlink.proxy(
'https://api.example.com/search?q=keyword&limit=10',
'GET',
{ 'Accept': 'application/json' }
);POST请求示例
// 创建新用户
const newUser = await kinlink.proxy(
'https://api.example.com/users',
'POST',
{
'Content-Type': 'application/json',
'Accept': 'application/json'
},
{
name: '张三',
email: '[email protected]',
department: '技术部'
}
);
console.log('创建的用户:', newUser);PUT/PATCH请求示例
// 更新用户信息(PUT)
const updatedUser = await kinlink.proxy(
'https://api.example.com/users/123',
'PUT',
{ 'Content-Type': 'application/json' },
{
name: '李四',
email: '[email protected]',
status: 'active'
}
);
// 部分更新(PATCH)
const patchedUser = await kinlink.proxy(
'https://api.example.com/users/123',
'PATCH',
{ 'Content-Type': 'application/json' },
{ status: 'inactive' }
);DELETE请求示例
// 删除用户
await kinlink.proxy(
'https://api.example.com/users/123',
'DELETE',
{ 'Accept': 'application/json' }
);
kinlink.formApi.showSuccess('用户删除成功');参数详解
url {string}
目标外部系统的完整URL地址。
要求: 必须是有效的HTTP/HTTPS URL
示例: 'https://api.example.com/users'
method {string}
HTTP请求方法,支持所有标准HTTP动词。
常用值: 'GET'、'POST'、'PUT'、'DELETE'、'PATCH'
注意: 方法名大小写不敏感
headers {object}
HTTP请求头对象,以键值对形式定义。
格式: {'Header-Name': 'Header-Value'}
常用头: 'Content-Type'、'Accept'、'Authorization'(如需要)
body {object|string|undefined}
请求体内容,根据请求类型和目标API要求设置。
对象类型: 自动序列化为JSON字符串 字符串类型: 直接作为请求体发送 undefined: 适用于GET等无需请求体的方法
返回值类型
返回: Promise<any>
解析值: 外部API返回的JSON对象或原始响应数据
异常: 网络错误、HTTP错误状态码、服务异常时抛出异常
安全机制
代理服务的安全设计和Token保护原理
Token隐藏机制
代理服务采用服务端代理架构,确保敏感信息的完全隐藏:
- 后端配置:所有认证信息在kinlink后台管理系统中配置
- 自动注入:服务端根据目标URL自动添加相应的认证头
- 前端透明:前端代码无需也无法获取任何敏感信息
- 安全传输:所有请求通过加密通道传输
跨域解决方案
通过服务端代理机制完全绕过浏览器的同源策略限制:
- 无CORS限制:可访问任何外部API,无需目标服务器支持CORS
- 完整头部支持:可发送任意请求头,包括自定义认证头
- 协议支持:支持HTTP和HTTPS协议的API调用
异常处理
错误情况的处理和最佳实践
错误类型
代理API可能遇到的错误情况:
- 网络错误:连接超时、DNS解析失败等
- HTTP错误:4xx客户端错误、5xx服务器错误
- 解析错误:响应数据格式无效
- 配置错误:目标URL未在后台配置认证信息
异常处理最佳实践
建议使用try-catch或.catch()方法处理异常:
// 推荐的异常处理方式
try {
const result = await kinlink.proxy(url, method, headers, body);
// 处理成功响应
console.log('API调用成功:', result);
} catch (error) {
// 处理异常情况
console.error('API调用失败:', error);
kinlink.formApi.showError('外部服务暂时不可用,请稍后重试');
}
// Promise链式调用方式
kinlink.proxy(url, method, headers, body)
.then(result => {
console.log('API调用成功:', result);
// 处理成功逻辑
})
.catch(error => {
console.error('API调用失败:', error);
kinlink.formApi.showError('外部服务请求失败');
});实际应用场景
代理API在不同业务场景中的应用
表单提交前验证
在表单提交前调用外部API进行数据验证或业务检查:
kinlink.events.on(kinlink.FormEvents.BEFORE_SUBMIT, async (data) => {
try {
const { values } = data;
// 通过代理安全调用外部API
const result = await kinlink.proxy(
'https://api.example.com/endpoint',
'POST',
{ 'Content-Type': 'application/json' },
{ foo: 'bar', ...values }
);
// 可根据result决定是否允许提交
if (!result.success) {
kinlink.formApi.showError('外部系统校验失败');
return false; // 阻止表单提交
}
} catch (error) {
kinlink.formApi.showError('外部系统请求失败');
return false; // 阻止表单提交
}
});典型应用场景
数据验证集成
用户信息验证示例:
// 验证员工工号是否存在
async function validateEmployeeId(employeeId) {
try {
const employee = await kinlink.proxy(
'https://hr.company.com/api/employees/' + employeeId,
'GET',
{ 'Accept': 'application/json' }
);
if (employee && employee.status === 'active') {
kinlink.formApi.setFieldValue('employeeName', employee.name);
kinlink.formApi.setFieldValue('department', employee.department);
return true;
} else {
kinlink.formApi.setFieldError('employeeId', '员工不存在或已离职');
return false;
}
} catch (error) {
kinlink.formApi.setFieldError('employeeId', '无法验证员工信息');
return false;
}
}
// 在字段变化时调用验证
kinlink.events.on(kinlink.FormEvents.FIELD_CHANGE, (event) => {
if (event.fieldCode === 'employeeId' && event.value) {
validateEmployeeId(event.value);
}
});业务规则检查示例:
// 检查预算申请是否超出限额
async function validateBudgetRequest(amount, category, department) {
try {
const budgetCheck = await kinlink.proxy(
'https://finance.company.com/api/budget/validate',
'POST',
{ 'Content-Type': 'application/json' },
{
amount: amount,
category: category,
department: department,
fiscalYear: new Date().getFullYear()
}
);
if (!budgetCheck.approved) {
kinlink.formApi.setFieldError('amount',
`申请金额超出预算限额,剩余额度:¥${budgetCheck.remaining}`);
return false;
}
kinlink.formApi.clearFieldError('amount');
return true;
} catch (error) {
kinlink.formApi.showError('预算验证服务暂时不可用');
return false;
}
}数据同步场景
CRM系统同步示例:
// 将客户信息同步到CRM系统
async function syncToCRM(customerData) {
try {
// 检查客户是否已存在
const existingCustomer = await kinlink.proxy(
`https://crm.company.com/api/customers/search?email=${customerData.email}`,
'GET',
{ 'Accept': 'application/json' }
);
if (existingCustomer.data.length > 0) {
// 更新现有客户
const updated = await kinlink.proxy(
`https://crm.company.com/api/customers/${existingCustomer.data[0].id}`,
'PUT',
{ 'Content-Type': 'application/json' },
customerData
);
kinlink.formApi.showSuccess('客户信息已更新到CRM系统');
} else {
// 创建新客户
const created = await kinlink.proxy(
'https://crm.company.com/api/customers',
'POST',
{ 'Content-Type': 'application/json' },
customerData
);
kinlink.formApi.showSuccess(`新客户已创建,CRM ID: ${created.id}`);
}
} catch (error) {
kinlink.formApi.showError('CRM同步失败:' + error.message);
}
}
// 在表单提交成功后同步到CRM
kinlink.events.on(kinlink.FormEvents.AFTER_SUBMIT, async (data) => {
const customerData = {
name: data.values.customerName,
email: data.values.email,
phone: data.values.phone,
company: data.values.company,
source: 'kinlink_form'
};
await syncToCRM(customerData);
});实时数据获取示例:
// 获取产品库存信息
async function loadProductInventory(productId) {
try {
const inventory = await kinlink.proxy(
`https://erp.company.com/api/inventory/${productId}`,
'GET',
{ 'Accept': 'application/json' }
);
// 更新表单中的库存信息
kinlink.formApi.setFieldValue('availableStock', inventory.quantity);
kinlink.formApi.setFieldValue('unitPrice', inventory.unitPrice);
// 根据库存情况显示提示
if (inventory.quantity < 10) {
kinlink.formApi.showWarning(`产品库存不足,仅剩 ${inventory.quantity} 件`);
}
// 如果缺货则禁用数量字段
if (inventory.quantity === 0) {
kinlink.formApi.disableField('quantity');
kinlink.formApi.setFieldError('quantity', '产品暂时缺货');
} else {
kinlink.formApi.enableField('quantity');
kinlink.formApi.clearFieldError('quantity');
}
} catch (error) {
kinlink.formApi.showError('无法获取库存信息');
}
}
// 产品选择变化时更新库存
kinlink.events.on(kinlink.FormEvents.FIELD_CHANGE, (event) => {
if (event.fieldCode === 'productId' && event.value) {
loadProductInventory(event.value);
}
});集成认证服务
用户权限验证示例:
// 检查用户操作权限
async function checkUserPermission(userId, action, resource) {
try {
const permission = await kinlink.proxy(
'https://auth.company.com/api/permissions/check',
'POST',
{ 'Content-Type': 'application/json' },
{
userId: userId,
action: action,
resource: resource
}
);
return permission.allowed;
} catch (error) {
console.error('权限检查失败:', error);
return false;
}
}
// 表单初始化时检查权限
kinlink.events.on(kinlink.FormEvents.INIT, async () => {
const currentUser = kinlink.formApi.getFieldValue('currentUserId');
// 检查编辑权限
const canEdit = await checkUserPermission(currentUser, 'edit', 'form_data');
if (!canEdit) {
// 禁用所有编辑字段
const editableFields = ['name', 'email', 'department', 'salary'];
editableFields.forEach(field => {
kinlink.formApi.disableField(field);
});
kinlink.formApi.showWarning('您没有编辑权限,表单为只读模式');
}
// 检查查看敏感信息权限
const canViewSalary = await checkUserPermission(currentUser, 'view', 'salary_info');
if (!canViewSalary) {
kinlink.formApi.hideField('salary');
}
});单点登录集成示例:
// SSO用户信息获取和表单预填充
async function initializeUserFromSSO() {
try {
// 获取当前SSO用户信息
const userInfo = await kinlink.proxy(
'https://sso.company.com/api/user/current',
'GET',
{ 'Accept': 'application/json' }
);
if (userInfo) {
// 预填充用户信息
kinlink.formApi.setFieldsValue({
employeeId: userInfo.employeeId,
fullName: userInfo.fullName,
email: userInfo.email,
department: userInfo.department,
manager: userInfo.managerName
});
// 隐藏用户自己无法修改的字段
kinlink.formApi.disableField('employeeId');
kinlink.formApi.disableField('email');
kinlink.formApi.showInfo('已自动填入您的基本信息');
}
} catch (error) {
kinlink.formApi.showError('无法获取用户信息,请手动填写');
}
}
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', initializeUserFromSSO);配置和部署
代理服务的配置要求和部署说明
后台配置要求
- URL映射配置:在kinlink后台配置目标API的URL模式
- 认证信息设置:配置对应的Token、API Key等认证信息
- 请求头模板:定义自动添加的认证头格式
- 访问权限控制:设置允许访问的API白名单
配置示例
基础URL映射配置
// kinlink后台配置示例(JSON格式)
{
"proxyConfigs": [
{
"name": "HR系统API",
"urlPattern": "https://hr.company.com/api/*",
"enabled": true,
"authType": "bearer",
"authToken": "undefined",
"rateLimiting": {
"requestsPerMinute": 60,
"burstLimit": 10
}
},
{
"name": "CRM系统API",
"urlPattern": "https://crm.company.com/api/*",
"enabled": true,
"authType": "apikey",
"authHeaders": {
"X-API-Key": "undefined",
"X-Client-ID": "kinlink-integration"
}
},
{
"name": "财务系统API",
"urlPattern": "https://finance.company.com/api/*",
"enabled": true,
"authType": "custom",
"authHeaders": {
"Authorization": "Custom undefined",
"X-Request-Source": "kinlink"
},
"allowedMethods": ["GET", "POST"],
"ipWhitelist": ["10.0.0.0/8"]
}
]
}环境变量设置
# .env 配置文件示例
# HR系统认证
HR_API_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# CRM系统认证
CRM_API_KEY=pk_live_1234567890abcdef
CRM_SECRET=sk_live_0987654321fedcba
# 财务系统认证
FINANCE_TOKEN=ft_abc123def456ghi789
# 代理服务配置
PROXY_TIMEOUT=30000
PROXY_MAX_REDIRECTS=5
PROXY_SSL_VERIFY=true
# 日志配置
LOG_LEVEL=info
LOG_PROXY_REQUESTS=true运行时配置检查
// 配置验证脚本示例
async function validateProxyConfiguration() {
const configs = [
{
name: 'HR API',
url: 'https://hr.company.com/api/health',
method: 'GET'
},
{
name: 'CRM API',
url: 'https://crm.company.com/api/ping',
method: 'GET'
}
];
const results = [];
for (const config of configs) {
try {
const startTime = Date.now();
const response = await kinlink.proxy(config.url, config.method, {});
const responseTime = Date.now() - startTime;
results.push({
name: config.name,
status: 'success',
responseTime: responseTime,
message: '配置正常'
});
} catch (error) {
results.push({
name: config.name,
status: 'error',
error: error.message,
message: '配置失败'
});
}
}
console.table(results);
return results;
}
// 在开发环境中验证配置
if (process.env.NODE_ENV === 'development') {
validateProxyConfiguration();
}安全最佳实践
网络安全配置
// 安全配置检查清单
const securityChecklist = {
// SSL/TLS验证
sslVerification: true,
// 请求头安全
securityHeaders: {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'X-XSS-Protection': '1; mode=block'
},
// 速率限制
rateLimiting: {
enabled: true,
windowMs: 60000, // 1分钟
maxRequests: 100,
skipSuccessfulRequests: false
},
// IP白名单(可选)
ipWhitelist: [
'192.168.1.0/24',
'10.0.0.0/8'
],
// 请求大小限制
maxRequestSize: '10mb',
// 超时设置
timeout: 30000
};
// 监控和告警配置
const monitoringConfig = {
// 错误率阈值
errorThreshold: 0.05, // 5%
// 响应时间阈值
responseTimeThreshold: 5000, // 5秒
// 告警邮箱
alertEmails: ['[email protected]'],
// 日志保留期限
logRetentionDays: 30
};Token轮换策略
// Token自动轮换示例
class TokenManager {
constructor() {
this.tokens = new Map();
this.refreshIntervals = new Map();
this.setupTokenRotation();
}
// 设置Token轮换
setupTokenRotation() {
const tokenConfigs = [
{ service: 'hr', refreshInterval: 24 * 60 * 60 * 1000 }, // 24小时
{ service: 'crm', refreshInterval: 12 * 60 * 60 * 1000 }, // 12小时
{ service: 'finance', refreshInterval: 6 * 60 * 60 * 1000 } // 6小时
];
tokenConfigs.forEach(config => {
this.scheduleTokenRefresh(config.service, config.refreshInterval);
});
}
// 计划Token刷新
scheduleTokenRefresh(service, interval) {
const refreshToken = async () => {
try {
await this.refreshTokenForService(service);
console.log(`${service} Token轮换成功`);
} catch (error) {
console.error(`${service} Token轮换失败:`, error);
// 发送告警
this.sendAlert(service, error);
}
};
// 立即刷新一次
refreshToken();
// 设置定期刷新
const intervalId = setInterval(refreshToken, interval);
this.refreshIntervals.set(service, intervalId);
}
// 刷新特定服务的Token
async refreshTokenForService(service) {
// 实现具体的Token刷新逻辑
// 这里应该调用各服务的Token刷新API
throw new Error('需要实现具体的Token刷新逻辑');
}
// 发送告警
sendAlert(service, error) {
// 实现告警发送逻辑
console.error(`告警: ${service} 服务Token轮换失败`, error);
}
}
// 初始化Token管理器
const tokenManager = new TokenManager();参数说明
方法参数类型
url{string}- 目标API的完整URL地址method{string}- HTTP请求方法名称headers{object}- 请求头键值对对象body{object|string|undefined}- 请求体内容
返回值类型
Promise<any>- 异步Promise对象,解析为API响应数据- 成功时解析为外部API的响应数据
- 失败时抛出包含错误信息的异常