Express代理轉(zhuǎn)發(fā)服務(wù)器實現(xiàn)
express的代理轉(zhuǎn)發(fā)
其實我的內(nèi)心關(guān)于這個Express,我的內(nèi)心是拒絕的,不是說,我對這個框架有什么看法,而是因為這個大作業(yè)的問題。是的我還是一個大三老菜雞,苦練 Java 全干開發(fā),Python 人工智能 整整 一坤年。期間拿了幾個獎,水了篇論文 而已。
那么這篇文章主要做的,其實很簡單就是,做個代理轉(zhuǎn)發(fā)。前端請求,先到express服務(wù)器,然后轉(zhuǎn)發(fā)到flask服務(wù)器,為什么非要轉(zhuǎn)發(fā)呢,原因很簡單,web作業(yè)非要用node平臺,沒辦法,但是我的服務(wù)已經(jīng)用flask做好了,當(dāng)然這個和我先前寫的那個微信聊天的不一樣哈,這個是另一個,是視覺識別算法,說到這個,我本人目前也在手寫一個全新的目標(biāo)檢測算法,希望可以起到不錯的效果,扯遠了。所以沒有辦法,只能做一個express的代理轉(zhuǎn)發(fā)。
但是呢,為了體現(xiàn)工作量,我在這個轉(zhuǎn)發(fā)服務(wù)器里面加了點東西:
就是這個,加點curd,不然不好混。
項目結(jié)構(gòu)
這個的話,更像是一個dome,所以的話,項目結(jié)構(gòu)非常簡單。
因為核心功能就一個,就是做轉(zhuǎn)發(fā),然后呢,加上一些配套的記錄就好了。
然后就是我們的數(shù)據(jù)庫還有頁面之類的。當(dāng)然整個項目還是使用這個生成工具先生成了一個模板工程的。
由于整個項目簡單,骨架也是生成的,所以我這邊就只說,它的一些核心實現(xiàn)了。
轉(zhuǎn)發(fā)
那么首先就是我們的核心,代理轉(zhuǎn)發(fā):
const proxy = require("http-proxy-middleware").createProxyMiddleware; app.use( "/", proxy( [`/api/**`], { target: `http://www.httpbin.org/anything/`, changeOrigin: true, onProxyReq: (proxyReq, req, res) => { // 在代理請求發(fā)送到目標(biāo)服務(wù)器之前,對請求頭進行修改 const sourceUrl = req.originalUrl; const targetUrl = "your address"; db.insertProxy(sourceUrl, targetUrl, (err, id) => { if (err) { console.error(err); } else { console.log(`New proxy request saved with ID ${id}.`); } }); }, onProxyRes: (proxyRes, req, res) => { // 在代理服務(wù)器收到目標(biāo)服務(wù)器的響應(yīng)后,對響應(yīng)頭進行修改 proxyRes.headers['x-custom-header'] = 'Huterox'; } }, ), );
轉(zhuǎn)發(fā)記錄
然后其實就是我們的轉(zhuǎn)發(fā)記錄的了。這里的話我使用的是sqlite3。
這邊把一些方法都封裝到了db.js當(dāng)中去了。
const sqlite3 = require('sqlite3').verbose(); // 創(chuàng)建數(shù)據(jù)庫連接 const db = new sqlite3.Database('./db.sqlite', err => { if (err) { console.error(err.message); } else { console.log('Connected to the db.sqlite database.'); } }); // 創(chuàng)建表 const createTable = () => { db.run( `CREATE TABLE IF NOT EXISTS proxies ( id INTEGER PRIMARY KEY AUTOINCREMENT, source_url TEXT NOT NULL, target_url TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )`, err => { if (err) { console.error(err.message); } else { console.log('Table proxies created successfully.'); } } ); }; //查找 const searchProxy = function(keyword, offset, limit, callback) { const pattern = `%${keyword}%`; const countSql = `SELECT COUNT(*) as count FROM proxies WHERE source_url LIKE ? OR target_url LIKE ?`; const sql = `SELECT * FROM proxies WHERE source_url LIKE ? OR target_url LIKE ? ORDER BY created_at DESC LIMIT ? OFFSET ?`; db.get(countSql, [pattern, pattern], (err, row) => { if (err) { callback(err, {}); return; } const totalCount = row.count; db.all(sql, [pattern, pattern, limit, offset], (err, rows) => { if (err) { callback(err); return; } const proxies = rows.map(row => ({ id: row.id, sourceUrl: row.source_url, targetUrl: row.target_url, createdAt: row.created_at, })); callback(null, { proxies, totalCount }); }); }); }; // 插入一條記錄 const insertProxy = (sourceUrl, targetUrl, callback) => { db.run(`INSERT INTO proxies (source_url, target_url) VALUES (?, ?)`, [sourceUrl, targetUrl], err => { if (err) { console.error(err.message); callback(err.message, null); } else { console.log('New proxy added successfully.'); db.get(`SELECT last_insert_rowid() as id`, (err, row) => { callback(null, row.id); }); } }); }; // 根據(jù) ID 查詢代理轉(zhuǎn)發(fā)記錄 const getProxyById = (id, callback) => { db.get(`SELECT * FROM proxies WHERE id = ?`, [id], (err, row) => { if (err) { console.error(err.message); callback(err.message, null); } else { console.log(`Proxy with ID ${id} found.`); callback(null, row); } }); }; // 查詢所有代理轉(zhuǎn)發(fā)記錄 const getAllProxies = callback => { db.all(`SELECT * FROM proxies ORDER BY id`, (err, rows) => { if (err) { console.error(err.message); callback(err.message, null); } else { console.log('All proxies fetched successfully.'); callback(null, rows); } }); }; // 更新代理轉(zhuǎn)發(fā)記錄 const updateProxyById = (id, sourceUrl, targetUrl, callback) => { db.run( `UPDATE proxies SET source_url = ?, target_url = ? WHERE id = ?`, [sourceUrl, targetUrl, id], err => { if (err) { console.error(err.message); callback(err.message, null); } else { console.log(`Proxy with ID ${id} updated successfully.`); callback(null, true); } } ); }; // 根據(jù) ID 刪除代理轉(zhuǎn)發(fā)記錄 const deleteProxyById = (id, callback) => { db.run(`DELETE FROM proxies WHERE id = ?`, [id], err => { if (err) { console.error(err.message); callback(err.message, null); } else { console.log(`Proxy with ID ${id} deleted successfully.`); callback(null, true); } }); }; createTable(); module.exports = { insertProxy, getProxyById, getAllProxies, searchProxy, updateProxyById, deleteProxyById };
當(dāng)然只有這個還不夠,我們還有對應(yīng)的curd的接口才行。
所以在app.js里面去注冊這些接口。
app.get('/logs/proxy', (req, res) => { const { keyword = '', offset = 0, limit = 10 } = req.query; db.searchProxy(keyword, Number(offset), Number(limit), (err, result) => { if (err) { console.error(err); res.status(500).send('Internal server error.'); } else { res.json({ rows: result.proxies, count: result.totalCount }); console.log("當(dāng)前記錄條數(shù):" + result.totalCount) } }); }); app.post('/logs/proxy', (req, res) => { const { sourceUrl, targetUrl } = req.body; db.insertProxy(sourceUrl, targetUrl, (err, row) => { if (err) { console.error(err); res.status(500).send('Internal server error.'); } else { res.json(row); } }); }); app.delete('/logs/proxy/:id', (req, res) => { const id = req.params.id; db.deleteProxy(id, (err) => { if (err) { console.error(err); res.status(500).send('Internal server error.'); } else { res.status(204).end(); } }); });
前端頁面
之后,就是我們的前端頁面,這個頁面的話,好辦,我們就直接使用html來寫了。 訪問/logs 就可以訪問頁面:
app.get('/logs', (req, res) => { res.sendFile(__dirname + '/public/logs.html'); });
對應(yīng)的html代碼如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>代理日志查看</title> <link rel="stylesheet" rel="external nofollow" > <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> </head> <style> /* 設(shè)置全局字體和顏色 */ #app { margin: 0 auto; width: 80%; } </style> <body> <div id="app"> <h1>代理日志</h1> <el-form inline> <el-form-item label="關(guān)鍵字"> <el-input v-model="keyword" placeholder="輸入關(guān)鍵字進行搜索"></el-input> </el-form-item> <el-form-item> <el-button type="primary" icon="el-icon-search" v-on:click="search">搜索</el-button> </el-form-item> </el-form> <el-table :data="records" stripe> <el-table-column prop="id" label="ID" width="100"></el-table-column> <el-table-column prop="sourceUrl" label="請求路徑" width="300"></el-table-column> <el-table-column prop="targetUrl" label="目標(biāo)地址" width="300"></el-table-column> <el-table-column prop="timestamp" label="時間" width="200"> <template slot-scope="scope">{{ new Date(scope.row.createdAt).toLocaleString() }}</template> </el-table-column> <el-table-column label="操作" width="200"> <template slot-scope="scope"> <el-button type="danger" icon="el-icon-delete" v-on:click="removeRecord(scope.row.id)">刪除</el-button> </template> </el-table-column> </el-table> <el-pagination layout="total, prev, pager, next" :total="total" v-on:current-change="changePage"></el-pagination> </div> <script> const app = new Vue({ el: '#app', data: { records: [], keyword: '', current: 1, pageSize: 10, total: 0 }, methods: { search: function() { this.current = 1; this.loadRecords(); }, removeRecord: function(id) { this.$confirm('確定刪除該記錄?') .then(() => { axios.delete(`/logs/proxy/${id}`) .then(() => { this.loadRecords(); this.$message.success('刪除成功!'); }) .catch(() => { this.$message.error('刪除失??!'); }); }) .catch(() => {}); }, changePage: function(page) { this.current = page; this.loadRecords(); }, loadRecords: function() { axios.get('/logs/proxy', { params: { keyword: this.keyword, offset: (this.current - 1) * this.pageSize, limit: this.pageSize } }) .then(res => { this.records = res.data.rows; this.total = res.data.count; }) .catch(err => console.error(err)); } }, mounted: function() { this.loadRecords(); } }); </script> </body> </html>
那么之后的話,這個簡單的代理轉(zhuǎn)發(fā)服務(wù)器就寫好了。強行加上一層,服了。
以上就是Express代理轉(zhuǎn)發(fā)服務(wù)器實現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Express代理轉(zhuǎn)發(fā)服務(wù)器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
簡述JS中forEach()、map()、every()、some()和filter()的用法
JS中常常需要對數(shù)組進行遍歷、迭代操作,而我們常用的就是for語句對數(shù)組進行迭代,下面這篇文章主要給大家介紹了關(guān)于JS中forEach()、map()、every()、some()和filter()的用法,需要的朋友可以參考下2022-05-05WEB泡泡堂2.0(圖形界面+電腦對玩)(javascript)
WEB泡泡堂2.0(圖形界面+電腦對玩)(javascript)2007-01-01JS實現(xiàn)仿餓了么在瀏覽器標(biāo)簽頁失去焦點時網(wǎng)頁Title改變
這篇文章主要介紹了JS實現(xiàn)仿餓了么在瀏覽器標(biāo)簽頁失去焦點時網(wǎng)頁Title改變,需要的朋友可以參考下2017-06-06JavaScript中的console.time()函數(shù)詳細(xì)介紹
這篇文章主要介紹了JavaScript中的console.time()函數(shù)詳細(xì)介紹,console.time()函數(shù)主要用來統(tǒng)計程序執(zhí)行時間,需要的朋友可以參考下2014-12-12