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('')
inapp.config(['$stateProvider'...
.added
<base href="/" />
inindex.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?
5 Answers
Answers 1
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
Answers 2
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
Answers 3
- You don't need Apache or Nginx to run NodeJs in development, just
node server.js
is enough - Express gave you that error because you are using a deprecated API
res.sendfile
please use res.sendFile (capital F) - Some info for doing SPA:
- When you have the '#' in your URL, the browser interpret it as a local reference and thus, won't send new request to the server
- By enabling
$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 url - Without the '#' (hash-bang) browser will interpret it as a new request and send it to server, so you have to map all requests from server to your SPA entry file
- For exact steps of replicating this behavior, consult this article: https://scotch.io/tutorials/pretty-urls-in-angularjs-removing-the-hashtag (the base href in your entry file is important)
Answers 4
var path = require('path');
app.use(express.static(path.join(__dirname, 'public'))); app.get('*', function(req, res){ res.sendFile(path.join(__dirname, './', 'views', 'index.html')); });
the above code solved my issue for mean stack
Answers 5
If 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?
0 comments:
Post a Comment