Express代理轉(zhuǎn)發(fā)服務(wù)器實(shí)現(xiàn)
express的代理轉(zhuǎn)發(fā)
其實(shí)我的內(nèi)心關(guān)于這個(gè)Express,我的內(nèi)心是拒絕的,不是說,我對這個(gè)框架有什么看法,而是因?yàn)檫@個(gè)大作業(yè)的問題。是的我還是一個(gè)大三老菜雞,苦練 Java 全干開發(fā),Python 人工智能 整整 一坤年。期間拿了幾個(gè)獎(jiǎng),水了篇論文 而已。
那么這篇文章主要做的,其實(shí)很簡單就是,做個(gè)代理轉(zhuǎn)發(fā)。前端請求,先到express服務(wù)器,然后轉(zhuǎn)發(fā)到flask服務(wù)器,為什么非要轉(zhuǎn)發(fā)呢,原因很簡單,web作業(yè)非要用node平臺,沒辦法,但是我的服務(wù)已經(jīng)用flask做好了,當(dāng)然這個(gè)和我先前寫的那個(gè)微信聊天的不一樣哈,這個(gè)是另一個(gè),是視覺識別算法,說到這個(gè),我本人目前也在手寫一個(gè)全新的目標(biāo)檢測算法,希望可以起到不錯(cuò)的效果,扯遠(yuǎn)了。所以沒有辦法,只能做一個(gè)express的代理轉(zhuǎn)發(fā)。
但是呢,為了體現(xiàn)工作量,我在這個(gè)轉(zhuǎn)發(fā)服務(wù)器里面加了點(diǎn)東西:

就是這個(gè),加點(diǎn)curd,不然不好混。
項(xiàng)目結(jié)構(gòu)
這個(gè)的話,更像是一個(gè)dome,所以的話,項(xiàng)目結(jié)構(gòu)非常簡單。

因?yàn)楹诵墓δ芫鸵粋€(gè),就是做轉(zhuǎn)發(fā),然后呢,加上一些配套的記錄就好了。
然后就是我們的數(shù)據(jù)庫還有頁面之類的。當(dāng)然整個(gè)項(xiàng)目還是使用這個(gè)生成工具先生成了一個(gè)模板工程的。
由于整個(gè)項(xiàng)目簡單,骨架也是生成的,所以我這邊就只說,它的一些核心實(shí)現(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ù)器之前,對請求頭進(jìn)行修改
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)頭進(jìn)行修改
proxyRes.headers['x-custom-header'] = 'Huterox';
}
},
),
);轉(zhuǎn)發(fā)記錄
然后其實(shí)就是我們的轉(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)然只有這個(gè)還不夠,我們還有對應(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();
}
});
});前端頁面
之后,就是我們的前端頁面,這個(gè)頁面的話,好辦,我們就直接使用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)鍵字進(jì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="時(shí)間" 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>
那么之后的話,這個(gè)簡單的代理轉(zhuǎn)發(fā)服務(wù)器就寫好了。強(qiáng)行加上一層,服了。
以上就是Express代理轉(zhuǎn)發(fā)服務(wù)器實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Express代理轉(zhuǎn)發(fā)服務(wù)器的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
深入理解JavaScript系列(46):代碼復(fù)用模式(推薦篇)詳解
這篇文章主要介紹了深入理解JavaScript系列(46):代碼復(fù)用模式(推薦篇)詳解,本文講解了原型繼承、復(fù)制所有屬性進(jìn)行繼承、混合(mix-in)、借用方法等模式,需要的朋友可以參考下2015-03-03
移動端觸屏幻燈片圖片切換插件idangerous swiper.js
這篇文章主要為大家詳細(xì)介紹了移動端觸屏幻燈片圖片切換插件idangerous swiper.js的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
JavaScript中數(shù)組隨機(jī)排序的實(shí)現(xiàn)詳解
這篇文章主要為大家詳細(xì)介紹了JavaScript中數(shù)組隨機(jī)排序的實(shí)現(xiàn),主要是利用原地算法和sort/shuffle算法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-11-11

