Edited at

vue-routerのルーティングURLからハッシュを除去しつつ、URL直接指定でも表示させる(Node, Express)

More than 1 year has passed since last update.


vue-routerのデフォルト設定

vue-routerはデフォルトだと、URLにハッシュが付くようです。

ex) /tasksのルーティングの場合: http://localhost/#/tasks


かっこ悪いのでハッシュを除去


  • ルーターのmodeを'history'にする事でハッシュが消える。 ex) http://localhost/tasks

  • history.pushState APIを利用したルーターのhistoryモードとなる


src/router.ts

import Vue from 'vue';

import Router from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';
import Tasks from './views/Tasks.vue';

Vue.use(Router);

export default new Router({
+ mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/about',
name: 'about',
component: About,
},
{
path: '/tasks',
name: 'tasks',
component: Tasks,
},
],
});



historyモードの副作用



  • http://localhost/tasks というURLを直接指定してページを開くと、サーバ側にルーティング設定が無いので404エラーとなる

参考)

HTML5 History モード | vue-routerガイド


対処法(Node.js, expressを利用している場合)


公式ガイドに従ってconnect-history-api-fallbackをインストール

yarn add connect-history-api-fallback


app.ts(app.jsをTypeScript化したソース)でconnect-history-api-fallbackをapp.useしておく


  • ルーティングに設定が無いURLを指定されたら、index.htmlを表示するフォールバック設定をする


src/app.ts

import { Router, NextFunction, Request, Response } from 'express';


import * as createError from 'http-errors';
import * as express from 'express';
import * as session from 'express-session';
import * as path from 'path';
import * as cookieParser from 'cookie-parser';
import * as logger from 'morgan';
import * as csrf from 'csurf';
import * as cors from 'cors';
import * as awsServerlessExpressMiddleware from 'aws-serverless-express/middleware';
+ import * as history from 'connect-history-api-fallback';

import { IndexController } from './controllers/index';
import { UserController } from './controllers/user';
import { TaskController } from './controllers/task';

/**
* Application.
*
* @class App
*/
export class App {
public app: express.Application;

/**
* Bootstrap the application.
*
* @static
* @return {ng.auto.IInjectorService} Returns the newly created injector for this app.
*/
public static bootstrap(): App {
return new App();
}

/**
* Constructor.
*
* @constructor
*/
constructor() {
this.app = express();

this.setConfig();

this.preRoutes();
this.setApiRoutes();
this.setRoutes();
this.postRoutes();

this.setErrorHandler();
}

/**
* Configure application
*
*/
private setConfig(): void {
this.app.use(awsServerlessExpressMiddleware.eventContext());

// this.app.set('views', path.join(__dirname, 'views'));
// this.app.set('view engine', 'jade');

this.app.use(logger('dev'));

this.app.use(express.json());
this.app.use(express.urlencoded({ extended: false }));

this.app.use(cookieParser());
this.app.use(session({
secret: 'todo1A2B3C$!',
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 60 * 60 * 1000
}
}));

+ this.app.use(history());

this.app.use(express.static(path.join(__dirname, '../client/dist')));
}

/**
* Pre process of routing.
*
*/
private preRoutes(): void {
this.app.all('/*', (req: Request, res: Response, next: NextFunction) => {
try {
console.log(`Pre:url=${req.url}&sessionID=${req.sessionID}&params=${JSON.stringify(req.params)}`);
next();
} catch (err) {
next(err);
}
});
}

/**
* Post process of routing.
*
*/
private postRoutes(): void {
this.app.all('/*', (req: Request, res: Response, next: NextFunction) => {
try {
console.log(`Post:url=${req.url}&sessionID=${req.sessionID}&params=${JSON.stringify(req.params)}`);
} catch (err) {
next(err);
}
});
}

/**
* Set routes.
*
*/
private setRoutes(): void {
this.app.use(csrf({ cookie: true }));

this.app.use('/', new IndexController().register());
this.app.use('/home', (req: Request, res: Response, next: NextFunction) => {
try {
res.redirect('/');
next();
} catch (err) {
next(err);
}
});
}

/**
* Create REST API routes
*
*/
private setApiRoutes(): void {
this.app.use(cors());

this.app.use('/api/users', new UserController().register());
this.app.use('/api/tasks', new TaskController().register());
}

/**
* Create Error handler
*
*/
private setErrorHandler(): void {
// Catch 404 and forward to error handler
this.app.use((req: Request, res: Response, next: NextFunction) => {
next(createError(404));
});

// Error handler
this.app.use((err: app.Error, req: Request, res: Response, next: NextFunction) => {
// Set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// Render the error page
res.status(err.status || 500);
res.render('error');
});
}
}



URL直接指定でアクセスしてみる

http://localhost/tasks

Screen Shot 2018-05-04 at 2.03.00.png


感想

Angularのルーティングでは、ハッシュ除去の設定しても、サーバ側で対処せずに

URL直接指定での表示できてたんで意識した事がなかった。

history.pushState APIというものを初めて知りました。