Node 轻量内网接口转发服务

51 阅读1分钟

背景: 合作商的接口只能在内网访问,需要做一下接口转发将数据转发到我们自己的服务器。

方案:Node服务轻量级实现,因为部署服务的这台服务器要做复杂算法操作,需要尽可能的节省空间,所以这里只用HTTPS + 调度器库实现,占用内存5-6MB。

  • 使用定时器定时从内网拉取接口A,转发到我们的接口B
  • 加上错误重试和内存检测。

mkdir my-server

cd my-server

npm init -y npm i node-schedule

const https = require('https');d
const schedule = require('node-schedule');

console.log('start');
const fetchDataInterval = 1000; // 间隔时间,单位为毫秒 (这里是每5秒执行一次)
let maxRetryAttempts = 3; // 最大重试次数
const maxMemoryUsageMB = 50; // 设置内存使用的阈值(以MB为单位)

function fetchDataAndForward() {
    console.log('fetchDataAndForward');

    // 从内网接口A获取数据
    const requestA = https.request('https://mock.apifox.cn/m1/926576-0-default/pet/1', { method: 'GET' }, (responseA) => {
        console.log('responseA.statusCode', responseA.statusCode)
        if ((requestA.statusCode  <= 200)  ||  (requestA.statusCode >= 300)) {
            console.error(`Error fetching data from internal API A. Status code: ${responseA.statusCode}`);
            return; // 终止请求
        }

        let data = '';
        responseA.on('data', (chunk) => {
            data += chunk;

            console.log('data', data);
        });

        responseA.on('end', () => {
            console.log('end', data);

            // 转发数据到外网接口B
            const optionsB = {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                }
            };

            const requestB = https.request('https://mock.apifox.cn/m1/926576-0-default/pet', optionsB, (responseB) => {
                if ((responseB.statusCode  <= 200)  ||  (responseB.statusCode >= 300)) {
                    console.error(`Error forwarding data to external API B. Status code: ${responseB.statusCode}`);
                    return; // 终止请求
                }

                responseB.on('data', (chunk) => {
                    console.log('Data forwarded successfully:', chunk.toString());
                });
            });

            requestB.write(data);
            requestB.end();
        });
    });

    requestA.end();

    requestA.on('error', (error) => {
        console.error('Error fetching data from internal API A:', error);

        // 添加重试逻辑
        if (maxRetryAttempts > 0) {
            console.log(`Retrying in ${interval / 1000} seconds...`);
            setTimeout(() => {
                console.log('Retrying...');
                fetchDataAndForward(); // 重新执行请求
                maxRetryAttempts--; // 减少重试次数
            }, fetchDataInterval);
        } else {
            console.log('Max retry attempts reached. Stopping retries.');
        }
    });
}

const controlMemoryUsage = (task) => {
    const memoryUsage = process.memoryUsage(); // 获取内存使用情况
    console.log(`Memory usage: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB`);

    if (memoryUsage.heapUsed / (1024 * 1024) > maxMemoryUsageMB) {
        console.log('Memory usage exceeded the threshold. Taking corrective action...');
        // 在内存使用超出阈值时,可以采取适当的措施

        return;
    }

    task(); // 执行数据拉取
};

const job = () => {
    controlMemoryUsage(fetchDataAndForward);
};

// 创建上午、中午和下午的任务
const morningJob = schedule.scheduleJob('00 08 * * *', job); // 每天上午 8:00
const noonJob = schedule.scheduleJob('00 12 * * *', job); // 每天中午 12:00
const afternoonJob = schedule.scheduleJob('00 16 * * *', job); // 每天下午 16:00