proxy-node
unknown
javascript
3 years ago
3.3 kB
8
Indexable
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const fs = require('fs-extra');
const path = require('path');
const crypto = require('crypto');
const minimist = require('minimist');
const chalk = require('chalk');
const app = express();
const argv = minimist(process.argv.slice(2));
if (!argv.targetUrl || !argv.port || !argv.mode) {
console.log(chalk.red('Usage: node index.js --targetUrl <target_url> --port <port> --mode <mode>'));
console.log('\n' + chalk.green('Modes:'));
console.log(' ' + chalk.blue('capture-only') + ': Only caches requests to the file system but does not read from them.');
console.log(' ' + chalk.blue('proxy-only') + ': Only hits the target URL and does not use caching.');
console.log(' ' + chalk.blue('mix') + ': Uses both caching and proxying.');
process.exit(1);
}
const TARGET_URL = argv.targetUrl;
const PORT = parseInt(argv.port, 10);
const MODE = argv.mode.toLowerCase();
if (!['capture-only', 'proxy-only', 'mix'].includes(MODE)) {
console.log(chalk.red('Invalid mode. Choose one of the following: capture-only, proxy-only, mix.'));
process.exit(1);
}
app.use(cors()); // Enable CORS for all routes
app.use(express.json()); // Parse JSON request bodies
const CACHE_DIR = './cache';
if (MODE !== 'proxy-only') {
// Create cache directory if it doesn't exist
fs.ensureDirSync(CACHE_DIR);
}
// Generate cache key based on the original URL
function generateCacheKey(req) {
return req.originalUrl.replace(/\//g, '__');
}
// Route for proxying and caching requests
app.all('*', async (req, res) => {
const { method, headers, body } = req;
const url = TARGET_URL + req.originalUrl;
const cacheKey = generateCacheKey(req);
const cacheFilePath = path.join(CACHE_DIR, cacheKey + '.json');
// If mode is 'mix' and cache file exists, return cached response
if (MODE === 'mix' && await fs.pathExists(cacheFilePath)) {
const cachedResponse = await fs.readJson(cacheFilePath);
return res.status(cachedResponse.status).set(cachedResponse.headers).send(cachedResponse.data);
}
// Remove host and connection headers to avoid conflicts
delete headers.host;
delete headers.connection;
try {
const axiosResponse = await axios({
method,
url,
headers,
data: body,
});
// Cache the response if mode is 'capture-only' or 'mix'
if (MODE !== 'proxy-only') {
await fs.writeJson(cacheFilePath, {
status: axiosResponse.status,
headers: axiosResponse.headers,
data: axiosResponse.data,
});
}
// Forward status, headers, and data from Axios response
res.status(axiosResponse.status).set(axiosResponse.headers).send(axiosResponse.data);
} catch (error) {
if (error.response) {
// Forward error status, headers, and data from Axios error response
res.status(error.response.status).set(error.response.headers).send(error.response.data);
} else {
// If the request failed for any other reason, return a 500 status code
res.status(500).send('An error occurred while proxying the request.');
}
}
});
app.listen(PORT, () => {
console.log(chalk.yellow(CORS proxy server with mode "${MODE}" listening on port ${PORT}));
});
Editor is loading...