Edit 1: Here is a mini code I made that reproduces the error. Please follow README.md
to install.
Edit 2: Finally, I found one solution. Besides $locationProvider.html5Mode(true);
($locationProvider.hashPrefix('')
is NOT necessary for me) and <base href="/" />
, I need to add the follows in routes/index.js
, rather than app.js
. Then, we do NOT need to add anything more to app.js
or nginx or apache like this thread mentions.
var express = require('express');
var router = express.Router();
var path = require('path');
... ...
router.get('*', function(req, res) {
res.sendfile('./views/index.html'); // load our public/index.html sendFile
// res.sendFile('index.html', { root: path.join(__dirname, 'views') }); // does not work
});
One problem is, in the server console, it gives express deprecated res.sendfile: Use res.sendFile instead routes/index.js:461:9
. But res.sendFile('index.html', { root: path.join(__dirname, 'views') });
can not help, it returns 404 error.
My express version is ~4.14.0
... does anyone know how to fix that?
OP:
I develop in Mac with Apache a MEAN-stack application that can be requested by
https://localhost:3000/#/home
. In production with an NGINX server, the application can be requested by
https://www.myapp.io/#/home
. The fragment-identifier #
is needed in all cases because of angular ui-router
.
So I wanted to make pretty url without #
(eg, https://www.myapp.io/home
, https://localhost:3000/home
) work. I have done the following:
added $locationProvider.html5Mode(true); $locationProvider.hashPrefix('')
in app.config(['$stateProvider'...
.
added <base href="/" />
in index.html
As a result, https://localhost:3000/#/home
changes automatically to https://localhost:3000/home
in the browser bar, similarly for https://www.myapp.io/#/home
.
However, directly entering https://localhost:3000/home
or https://www.myapp.io/home
in the browser will raise an error (I don't know how to turn previous <h1><%= message %></h1><h2><%= error.status %></h2><pre><%= error.stack %></pre>
in error.ejs
to error.html
, so I don't have more details).
So now, the goal is to make https://localhost:3000/home
and https://www.myapp.io/home
work.
By following this thread, I added the follows to app.js
:
app.use('/js', express.static(__dirname + '/js'));
app.use('/dist', express.static(__dirname + '/../dist'));
app.use('/css', express.static(__dirname + '/css'));
app.use('/partials', express.static(__dirname + '/partials'));
app.all('/*', function(req, res, next) {
res.sendFile('index.html', { root: __dirname });
});
And in Apache of Mac, here is my httpd-vhosts.conf
, after restarting apache
,
https://localhost:3000/home
still returns an error.
<VirtualHost *:443>
ServerName localhost
DocumentRoot "/Users/SoftTimur"
SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
SSLCertificateFile /etc/apache2/ssl/localhost.crt
SSLCertificateKeyFile /etc/apache2/ssl/localhost.key
<Directory "/Users/SoftTimur">
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
Require all granted
</Directory>
</VirtualHost>
In production, here is the NGINX server block. After restarting NGINX, https://www.myapp.io/home
still returns an error.
server {
listen 443 ssl;
server_name myapp.io www.myapp.io;
ssl_certificate /etc/letsencrypt/live/myapp.io/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.io/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:EC$
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
index index.html;
root /opt/myapp;
location / {
try_files $uri $uri/ /index.html;
}
location ~ /.well-known {
allow all;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Accept-Encoding "";
proxy_set_header Proxy "";
proxy_pass https://127.0.0.1:3000;
# These three lines added as per https://github.com/socketio/socket.io/issues/1942 to remove sock$
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Could anyone help?
try this in your express server
var express = require('express');
var app = express();
app.get('*', function (req, res) { res.sendFile(__dirname + '/views/index.html'); });
and in your angular app:
$locationProvider.hashPrefix('!').html5Mode({
enabled: true
});
$urlRouterProvider.otherwise('/');
and you still need the <base href="/">
in your index.html
let me know if this works for you
EDIT:
I just found your app in https://github.com/chengtie/mini-mean, looks like your app.use order is wrong. Please copy paste this in your express server and check if it's okay now. pastebin
This might useful stuff,
AngularJS routing without the hash '#'
Also, use this line in your express server file.
app.use(express.static(path.join(__dirname, 'client folder')));
this will directly finds your index.html file in that views folder and loads it
node server.js
is enoughres.sendfile
please use res.sendFile (capital F)$locationProvider.html5Mode(true)
you are now using html5 push state to navigate around your application history and (if I'm not mistaken you are happening to be using) angular effectively remove the '#' in urlIf it's just about the #. You can remove it in Angular itself.
Just inject locationProvider at your app entry and set htmlMode to true. In your index.html set the baseUrl.
$locationProvider.html5Mode(true)
And in you index.html add:
<base href="/" />
That will generate your urls without the #. Does that help?
©2020 All rights reserved.