Express 中基于子域(主机)的路由
Subdomain (host) based routing in Express
我用谷歌搜索了一段时间,但找不到任何有用的答案。我正在尝试为我的网站 api.example.com
上的 api 获取一个子域。但是,所有答案都说我需要更改我的 DNS 以将 api.example.com
重定向到 example.com/api
,这是我不想要的。是否可以只提供 api.
而不是重定向到 /api
?我该怎么做?
- 我正在使用快递。
- 我不想使用任何其他非内置包。
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter.js');
// security improvements
app.use(helmet());
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
app.use(/* API subdomain router... */)
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
绝对可以仅将子域 (api.example.com) 指向您的 api 服务器。
DNS 不控制子目录,因此 example.com/api
的 DNS 条目将无效
如果您有服务器的 IP 地址,则需要添加一条 A 记录,其值为:api.example.com
.
如果您的服务器有域名,则需要创建 CNAME 记录。
我建议您使用 nginx 并单独使用 api 服务。
但是由于某些原因你无法避免它(或者你不想要它,因为你只想尽快向客户展示原型)。
您可以编写中间件,从 header 捕获主机并转发到某个自定义路由器:
1) /middlewares/forwardForSubdomain.js
:
module.exports =
(subdomainHosts, customRouter) => {
return (req, res, next) => {
let host = req.headers.host ? req.headers.host : ''; // requested hostname is provided in headers
host = host.split(':')[0]; // removing port part
// checks if requested host exist in array of custom hostnames
const isSubdomain = (host && subdomainHosts.includes(host));
if (isSubdomain) { // yes, requested host exists in provided host list
// call router and return to avoid calling next below
// yes, router is middleware and can be called
return customRouter(req, res, next);
}
// default behavior
next();
}
};
2) api路由器为例/routers/apiRouter.js
:
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
// some operations here
});
module.exports = router;
3) 在 /
处理程序之前附加中间件:
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter');
// security improvements
app.use(helmet());
// ATTACH BEFORE ROUTING
const forwardForSubdomain = require('./middlewares/forwardForSubdomain');
const apiRouter = require('./routers/apiRouter');
app.use(
forwardForSubdomain(
[
'api.example.com',
'api.something.com'
],
apiRouter
)
);
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
P.S。它与 express-vhost package, look at the code
中的相同
我用谷歌搜索了一段时间,但找不到任何有用的答案。我正在尝试为我的网站 api.example.com
上的 api 获取一个子域。但是,所有答案都说我需要更改我的 DNS 以将 api.example.com
重定向到 example.com/api
,这是我不想要的。是否可以只提供 api.
而不是重定向到 /api
?我该怎么做?
- 我正在使用快递。
- 我不想使用任何其他非内置包。
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter.js');
// security improvements
app.use(helmet());
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
app.use(/* API subdomain router... */)
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
绝对可以仅将子域 (api.example.com) 指向您的 api 服务器。
DNS 不控制子目录,因此 example.com/api
的 DNS 条目将无效
如果您有服务器的 IP 地址,则需要添加一条 A 记录,其值为:api.example.com
.
如果您的服务器有域名,则需要创建 CNAME 记录。
我建议您使用 nginx 并单独使用 api 服务。
但是由于某些原因你无法避免它(或者你不想要它,因为你只想尽快向客户展示原型)。
您可以编写中间件,从 header 捕获主机并转发到某个自定义路由器:
1) /middlewares/forwardForSubdomain.js
:
module.exports =
(subdomainHosts, customRouter) => {
return (req, res, next) => {
let host = req.headers.host ? req.headers.host : ''; // requested hostname is provided in headers
host = host.split(':')[0]; // removing port part
// checks if requested host exist in array of custom hostnames
const isSubdomain = (host && subdomainHosts.includes(host));
if (isSubdomain) { // yes, requested host exists in provided host list
// call router and return to avoid calling next below
// yes, router is middleware and can be called
return customRouter(req, res, next);
}
// default behavior
next();
}
};
2) api路由器为例/routers/apiRouter.js
:
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
// some operations here
});
module.exports = router;
3) 在 /
处理程序之前附加中间件:
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter');
// security improvements
app.use(helmet());
// ATTACH BEFORE ROUTING
const forwardForSubdomain = require('./middlewares/forwardForSubdomain');
const apiRouter = require('./routers/apiRouter');
app.use(
forwardForSubdomain(
[
'api.example.com',
'api.something.com'
],
apiRouter
)
);
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
P.S。它与 express-vhost package, look at the code
中的相同