1
|
<h1 align="center">connect-history-api-fallback</h1>
|
2
|
<p align="center">Middleware to proxy requests through a specified index page, useful for Single Page Applications that utilise the HTML5 History API.</p>
|
3
|
|
4
|
[](https://travis-ci.org/bripkens/connect-history-api-fallback)
|
5
|
[](https://david-dm.org/bripkens/connect-history-api-fallback/master)
|
6
|
|
7
|
[](https://nodei.co/npm/connect-history-api-fallback/)
|
8
|
|
9
|
|
10
|
<h2>Table of Contents</h2>
|
11
|
|
12
|
<!-- TOC depthFrom:2 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
|
13
|
|
14
|
- [Introduction](#introduction)
|
15
|
- [Usage](#usage)
|
16
|
- [Options](#options)
|
17
|
- [index](#index)
|
18
|
- [rewrites](#rewrites)
|
19
|
- [verbose](#verbose)
|
20
|
- [htmlAcceptHeaders](#htmlacceptheaders)
|
21
|
- [disableDotRule](#disabledotrule)
|
22
|
|
23
|
<!-- /TOC -->
|
24
|
|
25
|
## Introduction
|
26
|
|
27
|
Single Page Applications (SPA) typically only utilise one index file that is
|
28
|
accessible by web browsers: usually `index.html`. Navigation in the application
|
29
|
is then commonly handled using JavaScript with the help of the
|
30
|
[HTML5 History API](http://www.w3.org/html/wg/drafts/html/master/single-page.html#the-history-interface).
|
31
|
This results in issues when the user hits the refresh button or is directly
|
32
|
accessing a page other than the landing page, e.g. `/help` or `/help/online`
|
33
|
as the web server bypasses the index file to locate the file at this location.
|
34
|
As your application is a SPA, the web server will fail trying to retrieve the file and return a *404 - Not Found*
|
35
|
message to the user.
|
36
|
|
37
|
This tiny middleware addresses some of the issues. Specifically, it will change
|
38
|
the requested location to the index you specify (default being `/index.html`)
|
39
|
whenever there is a request which fulfills the following criteria:
|
40
|
|
41
|
1. The request is a GET request
|
42
|
2. which accepts `text/html`,
|
43
|
3. is not a direct file request, i.e. the requested path does not contain a
|
44
|
`.` (DOT) character and
|
45
|
4. does not match a pattern provided in options.rewrites (see options below)
|
46
|
|
47
|
## Usage
|
48
|
|
49
|
The middleware is available through NPM and can easily be added.
|
50
|
|
51
|
```
|
52
|
npm install --save connect-history-api-fallback
|
53
|
```
|
54
|
|
55
|
Import the library
|
56
|
|
57
|
```javascript
|
58
|
var history = require('connect-history-api-fallback');
|
59
|
```
|
60
|
|
61
|
Now you only need to add the middleware to your application like so
|
62
|
|
63
|
```javascript
|
64
|
var connect = require('connect');
|
65
|
|
66
|
var app = connect()
|
67
|
.use(history())
|
68
|
.listen(3000);
|
69
|
```
|
70
|
|
71
|
Of course you can also use this piece of middleware with express:
|
72
|
|
73
|
```javascript
|
74
|
var express = require('express');
|
75
|
|
76
|
var app = express();
|
77
|
app.use(history());
|
78
|
```
|
79
|
|
80
|
## Options
|
81
|
You can optionally pass options to the library when obtaining the middleware
|
82
|
|
83
|
```javascript
|
84
|
var middleware = history({});
|
85
|
```
|
86
|
|
87
|
### index
|
88
|
Override the index (default `/index.html`)
|
89
|
|
90
|
```javascript
|
91
|
history({
|
92
|
index: '/default.html'
|
93
|
});
|
94
|
```
|
95
|
|
96
|
### rewrites
|
97
|
Override the index when the request url matches a regex pattern. You can either rewrite to a static string or use a function to transform the incoming request.
|
98
|
|
99
|
The following will rewrite a request that matches the `/\/soccer/` pattern to `/soccer.html`.
|
100
|
```javascript
|
101
|
history({
|
102
|
rewrites: [
|
103
|
{ from: /\/soccer/, to: '/soccer.html'}
|
104
|
]
|
105
|
});
|
106
|
```
|
107
|
|
108
|
Alternatively functions can be used to have more control over the rewrite process. For instance, the following listing shows how requests to `/libs/jquery/jquery.1.12.0.min.js` and the like can be routed to `./bower_components/libs/jquery/jquery.1.12.0.min.js`. You can also make use of this if you have an API version in the URL path.
|
109
|
```javascript
|
110
|
history({
|
111
|
rewrites: [
|
112
|
{
|
113
|
from: /^\/libs\/.*$/,
|
114
|
to: function(context) {
|
115
|
return '/bower_components' + context.parsedUrl.pathname;
|
116
|
}
|
117
|
}
|
118
|
]
|
119
|
});
|
120
|
```
|
121
|
|
122
|
The function will always be called with a context object that has the following properties:
|
123
|
|
124
|
- **parsedUrl**: Information about the URL as provided by the [URL module's](https://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost) `url.parse`.
|
125
|
- **match**: An Array of matched results as provided by `String.match(...)`.
|
126
|
- **request**: The HTTP request object.
|
127
|
|
128
|
|
129
|
### verbose
|
130
|
This middleware does not log any information by default. If you wish to activate logging, then you can do so via the `verbose` option or by specifying a logger function.
|
131
|
|
132
|
```javascript
|
133
|
history({
|
134
|
verbose: true
|
135
|
});
|
136
|
```
|
137
|
|
138
|
Alternatively use your own logger
|
139
|
|
140
|
```javascript
|
141
|
history({
|
142
|
logger: console.log.bind(console)
|
143
|
});
|
144
|
```
|
145
|
|
146
|
### htmlAcceptHeaders
|
147
|
Override the default `Accepts:` headers that are queried when matching HTML content requests (Default: `['text/html', '*/*']`).
|
148
|
|
149
|
```javascript
|
150
|
history({
|
151
|
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
|
152
|
})
|
153
|
```
|
154
|
|
155
|
### disableDotRule
|
156
|
Disables the dot rule mentioned above:
|
157
|
|
158
|
> […] is not a direct file request, i.e. the requested path does not contain a `.` (DOT) character […]
|
159
|
|
160
|
```javascript
|
161
|
history({
|
162
|
disableDotRule: true
|
163
|
})
|
164
|
```
|