我在構建 NodeJS express API 時遇到了一些錯誤(?)。顯然,一些端點相互重疊,這意味著我無法到達它們,請求在超時之前不會結束。
前任:
const load_dirs = (dirs, filename) => {
const router_files = readdirSync(`./${dirs}`).filter(file => file.endsWith(`${filename}.js`));
router_files.forEach(file => {
const {
getUsers, getUser, addUser, editUser, removeUser, loginUser, updateUserStatus
} = require(`../${dirs}/${file}`);
router
.route('/')
.get(cors(corsOptions), getUsers)
.post(cors(corsOptions), addUser);
router
.route('/login')
.post(cors(corsOptions), loginUser);
router
.route('/:userId')
.get(cors(corsOptions), getUser)
.post(cors(corsOptions), editUser)
.put(cors(corsOptions), removeUser);
router
.route('/:userId/status')
.post(cors(corsOptions), updateUserStatus);
});
}
['methods'].forEach(e => load_dirs(e, 'users'));
module.exports = (router);
如果登錄方法高于通過 Id 獲取用戶,我無法通過 Id 訪問用戶,反之亦然。而且由于這是一種使用節點的獨特方式(還沒有找到其他使用它的人),我無法弄清楚......
我錯過了什么?提前致謝!
編輯1:
根據評論中的要求,我將getUsers方法留在這里:
exports.getUsers = async (req, res, next) => {
try {
await new Promise(async (resolved, rejected) => {
let conn;
try {
conn = await db.pool.getConnection();
const result = await conn.query(`
SELECT * FROM users
`)
.then((resp) => {
if (!resp.length) {
res
.status(200)
.json({ success: true, message: general.noResults });
resolved(resp);
return;
}
const data = resp;
res
.status(200)
.json({ success: true, utilizadores: data });
resolved(resp);
})
.catch ((err) => {
if (mode() === 'development' || mode() === 'test') console.log(`Error: ${ err }.`);
res
.status(400)
.json({ success: true, message: general.badRequest });
rejected(err);
})
} catch (err) {
if (mode() === 'development' || mode() === 'test') console.log(`Error: ${ err }`);
res
.status(400)
.json({ success: false, message: general.badRequest });
rejected(err);
} finally {
if (conn) {
conn.end();
}
}
})
.then((message) => {
if (mode() === 'development' || mode() === 'test') console.log(message);
})
.catch((err) => {
if (mode() === 'development' || mode() === 'test') console.log(err);
});
} catch (err) {
if (mode() === 'development' || mode() === 'test') console.log(`Error: ${ err }.`);
res
.status(400)
.json({ success: false, message: general.badRequest });
}
}
uj5u.com熱心網友回復:
回圈是問題所在。我猜你正在嘗試為每個檔案設定一個路由。您不需要這樣做,因為您可以使用路由引數來替換檔案訪問代碼中的 userId。
import express from 'express';
const app = express();
const router = express.Router();
app.use(router);
const port = 3000;
const render1 = (req, res) => {
res.send(`Render 1 says: hello world`);
}
const render2 = (req, res) => {
res.send(`Render 2 says: logging in user...`);
}
const render3 = (req, res) => {
res.send(`Render 3 says: reading user data from file ./userdata/${req.params.userId}.json`);
}
const render4 = (req, res) => {
res.send(`Render 4 says: User ${req.params.userId} is logged in.`);
}
router.route('/').get(render1);
router.route('/login').get(render2);
router.route('/:userId').get(render3);
router.route('/:userId/status').get(render4);
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
uj5u.com熱心網友回復:
這種結構:
router
.route('/:userId')
.get(cors(corsOptions), getUser)
.post(cors(corsOptions), editUser)
.put(cors(corsOptions), removeUser);
創建一個通配符路由,匹配任何具有頂級路徑的 http 請求,例如:
/abc
/xxx
/123
因此,當您完成回圈的第一次迭代并創建這些頂級通配符路由中的第一個時,它將優先于在其之后添加到路由器的任何其他頂級路由。因此,它將為嘗試定義處理程式的回圈的未來迭代請求/login。
但是,整個模型被破壞了。即使您洗掉了通配符路由,這也不是唯一的問題。由于回圈的每次迭代只是一遍又一遍地定義完全相同的路線,因此在回圈的第一次迭代中定義的路線將優先于回圈的后續迭代中的所有其他路線。
您后續的回圈迭代需要定義不同的路線。如果我們洗掉您在此處遇到的所有復雜情況并僅顯示:
app.get("/login", someHandler1);
app.get("/login", someHandler2);
然后,第二個定義將永遠沒有機會看到/login路由,除非 someHandler1 碰巧決定不發送回應而是呼叫next()以將控制權傳遞到鏈上。
因此,在回圈中一遍又一遍地定義相同路線的整個模型似乎存在缺陷。此外,我傾向于避免使用頂級通配符路由,因為它會在您擴展功能時與其他頂級路由發生沖突。相反,要么執行/id/:userId或定義僅匹配頂級 userId 的正則運算式,但為不匹配該正則運算式的其他頂級路由留出空間。
要提出解決方案,我必須更好地了解當您有多個檔案具有所有相同的匯出請求處理程式和所有相同的路由路徑時,您究竟想要做什么。從表面上看,這對我來說毫無意義。您不會多次處理完全相同的傳入請求。您處理一次,因此需要一段代碼(而不是 N 段代碼)來處理任何給定的路線。
僅供參考,這是您getUsers()功能的簡化版本。您不需要在承諾中進行包裝,也不需要太多重復的錯誤處理:
exports.getUsers = async (req, res, next) => {
let conn;
try {
conn = await db.pool.getConnection();
const result = await conn.query(`SELECT * FROM users`);
if (!result.length) {
res.json({ success: true, message: general.noResults });
} else {
res.json({ success: true, utilizadores: results });
}
} catch(err) {
if (mode() === 'development' || mode() === 'test') console.log(`Error:`, err);
res.status(400).json({ success: true, message: general.badRequest });
} finally {
if (conn) {
conn.end();
}
}
});
變更摘要:
- 洗掉
await new Promise()包裝,因為這不是必需的 - 洗掉
.then(),.catch()所以我們只使用awaitandtry/catch - 將所有錯誤處理放在一個 catch 塊中
- 將所有錯誤處理程式合并到一個地方
- 修復錯誤物件的日志記錄
- 洗掉,
.status(200)因為 200 已經是默認值。
僅供參考,我認為您確實想要記錄錯誤,即使在生產中,而不僅僅是在開發中。如果您開始在部署的生產服務器中遇到問題,您將需要日志資訊來告訴您實際的內部錯誤是什么。因此,我建議您洗掉if僅在開發或測驗中記錄錯誤的內容。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/406426.html
標籤:
