简体   繁体   中英

Subdomain (host) based routing in Express

I've been Googling for some time, but can't find any useful answers. I'm trying to get a subdomain for an api on my website api.example.com . However, all answers said that I needed to change my DNS to redirect api.example.com to example.com/api , which I don't want. Is it possible to just serve api. instead of redirect to /api ? How would I go about doing that?

  1. I'm using express.
  2. I don't want to use any other packages that aren't built-in.
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"));
})

I recommend You to use nginx and separate api service.

But because of some reasons You cannot avoid it (or You don't want it, cause You just want show prototype to customer ASAP).

You can write middleware that will catch host from header and forward to some custom router:

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 router as an example /routers/apiRouter.js :

const express = require('express');
const router = express.Router();

router.get('/users', (req, res) => {
  // some operations here
});

module.exports = router;

3) attach middleware before / handler:

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"));
})

PS It does the same that in express-vhost package, look at the code

There is an official vhost plugin for Express.js: https://github.com/expressjs/vhost

What you are describing, having multiple domains/hostnames hosted/handled by a single server, is typically referred to as a "vhost" (virtual host).

It will definitely be possible to point just the subdomain (api.example.com) to your api server.

DNS doesn't control subdirectories so a DNS entry of example.com/api would be invalid

If you have an IP address for your server you will need to add an A record with the value: api.example.com .

If you have a domain name for your server you will need to create a CNAME record.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM