Che*_*erd 7 api middleware node.js express
对于路由,我希望我的中间件将请求在/ html文件夹中定义的路由传递给服务器HTML(ejs),如果头Content-Type是application/json,则使用/ api文件夹中定义的路由.
但我不想在每条路线中定义它.所以我不是在寻找定义一些req.api属性的中间件,我可以在每个路由中检查它
app.get('/', function(req, res) {
if(req.api_call) {
// serve api
} else {
// serve html
}
});
Run Code Online (Sandbox Code Playgroud)
但我喜欢这样的事情:
// HTML folder
app.get('/', function(req, res) {
res.send('hi');
});
// API folder
app.get('/', function(req, res) {
res.json({message: 'hi'});
});
Run Code Online (Sandbox Code Playgroud)
这是可能的,如果是这样,我该怎么做?
我希望它能像这样工作:
app.use(checkApiCall, apiRouter);
app.use(checkHTMLCall, htmlRouter);
Run Code Online (Sandbox Code Playgroud)
您可以在Express链中插入第一个中间件,一个中间件处理程序,它检查请求类型,然后req.url通过向其添加前缀路径将其修改为伪URL.然后,此修改将强制该请求仅转到特定路由器(设置为处理该特定URL前缀的路由器).我已使用以下代码在Express中验证了此功能:
var express = require('express');
var app = express();
app.listen(80);
var routerAPI = express.Router();
var routerHTML = express.Router();
app.use(function(req, res, next) {
// check for some condition related to incoming request type and
// decide how to modify the URL into a pseudo-URL that your routers
// will handle
if (checkAPICall(req)) {
req.url = "/api" + req.url;
} else if (checkHTMLCall(req)) {
req.url = "/html" + req.url;
}
next();
});
app.use("/api", routerAPI);
app.use("/html", routerHTML);
// this router gets hit if checkAPICall() added `/api` to the front
// of the path
routerAPI.get("/", function(req, res) {
res.json({status: "ok"});
});
// this router gets hit if checkHTMLCall() added `/api` to the front
// of the path
routerHTML.get("/", function(req, res) {
res.end("status ok");
});
Run Code Online (Sandbox Code Playgroud)
注意:我没有填写代码,checkAPICall()或者checkHTMLCall()因为您没有完全具体说明您希望这些代码如何工作.我在自己的测试服务器中嘲笑它们,看看这个概念是否有效.我假设您可以为这些函数提供适当的代码或替换您自己的if语句.
事先答复
我刚刚确认您可以更改req.urlExpress中间件,因此如果您有一些修改req.url它的中间件,它将影响该请求的路由.
// middleware that modifies req.url into a pseudo-URL based on
// the incoming request type so express routing for the pseudo-URLs
// can be used to distinguish requests made to the same path
// but with a different request type
app.use(function(req, res, next) {
// check for some condition related to incoming request type and
// decide how to modify the URL into a pseudo-URL that your routers
// will handle
if (checkAPICall(req)) {
req.url = "/api" + req.url;
} else if (checkHTMLCall(req)) {
req.url = "/html" + req.url;
}
next();
});
// this will get requests sent to "/" with our request type that checkAPICall() looks for
app.get("/api/", function(req, res) {
res.json({status: "ok"});
});
// this will get requests sent to "/" with our request type that checkHTMLCall() looks for
app.get("/html/", function(req, res) {
res.json({status: "ok"});
});
Run Code Online (Sandbox Code Playgroud)
较旧的答案
我能够在这样的快递面前成功地发出请求回调,并且看到它成功地修改了传入的URL,然后影响快速路由,如下所示:
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(function(req, res) {
// test modifying the URL before Express sees it
// this could be extended to examine the request type and modify the URL accordingly
req.url = "/api" + req.url;
return app.apply(this, arguments);
});
server.listen(80);
app.get("/api/", function(req, res) {
res.json({status: "ok"});
});
app.get("/html/", function(req, res) {
res.end("status ok");
});
Run Code Online (Sandbox Code Playgroud)
这个例子(我测试过的)只是硬连线在URL的前面添加"/ api",但您可以自己检查传入的请求类型,然后根据需要进行URL修改.我还没有探究是否可以完全在Express中完成.
在这个例子中,当我请求"/"时,我被赋予了JSON.
为了表达我的想法,我想要易于阅读的路线,而无需.json到处都有后缀。
router.get("/foo", HTML_ACCEPTED, (req, res) => res.send("<html><h1>baz</h1><p>qux</p></html>"))
router.get("/foo", JSON_ACCEPTED, (req, res) => res.json({foo: "bar"}))
Run Code Online (Sandbox Code Playgroud)
以下是这些中间件的工作方式。
function HTML_ACCEPTED (req, res, next) { return req.accepts("html") ? next() : next("route") }
function JSON_ACCEPTED (req, res, next) { return req.accepts("json") ? next() : next("route") }
Run Code Online (Sandbox Code Playgroud)
我个人认为这是非常可读的(因此是可维护的)。
$ curl localhost:5000/foo --header "Accept: text/html"
<html><h1>baz</h1><p>qux</p></html>
$ curl localhost:5000/foo --header "Accept: application/json"
{"foo":"bar"}
Run Code Online (Sandbox Code Playgroud)
笔记:
HTML路由放在路由之前,JSON因为有些浏览器会接受 HTML或JSON,所以它们会先列出哪个路由。我希望 API 用户能够理解和设置 Accept 标头,但我不希望浏览器用户能够理解和设置,因此浏览器会获得偏好。next('route'). 简而言之,next()跳到同一路由中的下一个中间件,同时next('route')跳出该路由并尝试下一个。