Handle MEAN stack application address without '#' snippet

Edit 1: Here is the mini-code I did it to reproduce the bug. Follow README.md

to install.

Edit 2: Finally I found one solution. Also, $locationProvider.html5Mode(true);

( $locationProvider.hashPrefix('')

NOT NECESSARY for me) and <base href="/" />

, I need to add the following in routes/index.js

, not app.js

. Then we don't need to add anything else to app.js

either nginx or apache like this thread .

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: 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't help it, it returns 404 error.

My express version ~4.14.0

... Does anyone know how to fix this?

OP:

I am developing on Mac with Apache a MEAN stack application that can be queried https://localhost:3000/#/home

. In production with an NGINX server, the application can be requested   https://www.myapp.io/#/home

. The fragment identifier is #

required in all cases because of angular ui-router

.

So, I wanted to make a nice url without #

(eg https://www.myapp.io/home

, https://localhost:3000/home

). I did the following:

  • added $locationProvider.html5Mode(true); $locationProvider.hashPrefix('')

    in app.config(['$stateProvider'...

    .

  • added <base href="/" />

    toindex.html

As a result, it https://localhost:3000/#/home

automatically changes to https://localhost:3000/home

in the browser bar, similar to https://www.myapp.io/#/home

.

However, direct entry https://localhost:3000/home

or https://www.myapp.io/home

in the browser will throw an error (I don't know how to turn the previous one <h1><%= message %></h1><h2><%= error.status %></h2><pre><%= error.stack %></pre>

into error.ejs

before error.html

), so I don't have more details).

So, now you need to do https://localhost:3000/home

and https://www.myapp.io/home

.

Following this thread , I added the following 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 on Apache Mac, here's mine httpd-vhosts.conf

, after restarting apache

, https://localhost:3000/home

still returning 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, this is an NGINX server block. NGINX https://www.myapp.io/home

still returns error after restarting .

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

      

Can anyone please help?

+3


source to share


4 answers


try this on 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 <base href="/">

in your index.html

let me know if it works for you

EDIT:

I just found your app at https://github.com/chengtie/mini-mean , it looks like your app.use order is wrong. Copy this to your express server and check if it's good now. pastebin

0


source


This can be helpful,

Angular routing without hash '#'



Also, use this line in express server file. app.use(express.static(path.join(__dirname, 'client folder')));

this will directly find your index.html file in that views folder and load it

0


source


  • You don't need Apache or Nginx to run NodeJs in development, just node server.js

    enough
  • Express gave you this error because you are using a deprecated API res.sendfile

    , please use res.sendFile (capital F)
  • Additional information for SPA:
    • When you have a "#" in your url, the browser interprets it as a local link and therefore won't send a new request to the server
    • By enabling $locationProvider.html5Mode(true)

      , you are now using html5 push state to navigate through app history and (if I'm not mistaken what you are using) angular effectively remove the '#' in url
    • Without browser '#' (hash-bang) it will interpret it as a new request and send it to the server, so you need to map all requests from the server to your SPA login file
    • For the exact steps to replicate this behavior refer to this article: https://scotch.io/tutorials/pretty-urls-in-angularjs-removing-the-hashtag (the base href value in the input file is important)
0


source


If it's around #. You can remove it in Angular yourself.

Just inject locationProvider into your app entry and set htmlMode to true. In your index.html, set the baseUrl.

$locationProvider.html5Mode(true)

      

And you have index.html add:

<base href="/" />

      

This will generate your urls without #. Does it help?

-1


source







All Articles