AngularJS Node app downloads instead of loading in

2019-07-31 18:06发布

问题:

Whenever I try loading my AngularJS webpage (on a node js + express server) through http://localhost:3000, Internet Explorer just tries to download it with a random name and no file extension, instead of showing the actual page.

I can't even check the console for errors, because the download attempt seems to start before even trying to load it as a webpage.

The website works perfectly on both Firefox and Chrome. I am using Internet Explorer 11, so it's not even an old version.

I tried running my index through the W3 Validator, and the only errors it points out in the DOM are the Angular directives and tags (which are not really errors).

I tried changing the DOCTYPE from just a simple <!DOCTYPE html> to this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">

And this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

... and this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

To no effect.

As suggested in other questions, I also tried serving my page as "text/plain" rather than "text/html" in my node server, but that didn't help either.

Here's the html for my index:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="it">
    <head>
        <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
        <!-- Angular Material CSS now available via Google CDN; version 1.0.7 used here -->
        <link rel="stylesheet" href="./modules/angular-material/angular-material.min.css"/>
        <link rel="stylesheet" href="./css/style.css"/>
        <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
    <link rel="icon" href="icons/favicon.ico" type="image/x-icon"/>
        <base href="/"/>
        <title>Area Clienti</title>
        <script src="./modules/angular/angular.js" type="text/javascript"></script>

        <script src="./modules/ngstorage/ngStorage.js" type="text/javascript"></script>

        <script src="./modules/angular-aria/angular-aria.min.js" type="text/javascript"></script>
        <script src="./modules/angular-animate/angular-animate.min.js" type="text/javascript"></script>

        <script src="./modules/angular-material/angular-material.min.js" type="text/javascript"></script>

        <script src="./modules/angular-ui-router/release/angular-ui-router.min.js" type="text/javascript"></script>
        <script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.core.min.js" type="text/javascript"></script>
        <script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.dsr.min.js" type="text/javascript"></script>
        <script src="./modules/ui-router-extras/release/modular/ct-ui-router-extras.sticky.min.js" type="text/javascript"></script>

        <script src="./modules/pdfmake/build/pdfmake.min.js" type="text/javascript"></script>
        <script src="./modules/pdfmake/build/vfs_fonts.js" type="text/javascript"></script>

        <script src="./modules/angular-messages/angular-messages.min.js" type="text/javascript"></script>
        <script src="http://ngmaterial.assets.s3.amazonaws.com/svg-assets-cache.js" type="text/javascript"></script>

        <script src="./js/client.js" type="text/javascript"></script>
    </head>
    <body ng-app="App" ng-controller="AppCtrl" ng-view ui-view ng-cloak layout="row">
    </body>
</html>

The script tags were in the body before, I tried putting them in the head to see if that would have helped, but it didn't.

What might be the issue here? And why is it so painful to make stuff work on IE?

EDIT: here's the server code.

var express = require("express");
var fs = require('fs');
var xml2js = require("./node_modules/xml2js");
var auth = require("./authenticator.js");
var bodyParser = require('body-parser');

var app=express();

//app.use(express.static('pages'));

var server = app.listen(3000, function(){
   var host = server.address().address;
   var port = server.address().port;
});

var jsonParser = bodyParser.json();       // to support JSON-encoded bodies

var urlencodedParser = bodyParser.urlencoded({     // to support URL-encoded bodies
    extended: true
}); 
app.get('/', function(req, res){
    sendFile(res, './index.html', getHeader('text/plain'));
});

app.use('/font/', express.static('./font/'));
app.use('/modules/', express.static('./node_modules/'));
app.use('/css/', express.static('./css/'));
app.use('/views/', express.static('./views/'));
app.use('/img/', express.static('./img/'));
app.use('/js/', express.static('./js/'));

function sendFile(res, path, header){
    fs.readFile(path, function(err, content){
        if(err) {
            console.log("\nErrore caricando " + path + " - err: " + err);
            //pageNotFound(res, "error");
        }
        else sendToClient(content, res, 200, header);
    });
}

function getHeader(type){
    return {"Content-Type": type};
}

function sendToClient(data, res, code, type){
    res.writeHead(code, getHeader(type));
    (type === "text/html" || type === "text") ? res.end(data, "utf-8") : res.end(data);
}

Plus a bunch of other POST and GET services which I think are not relevant


UPDATE: I managed to get it to say something in the developer console. This is the error:

(translation: impossible to open http://localhost:3000/) It still tries to download the page.


UPDATE 2:

I managed to find out what the issue was: for some reason, the Content-Type header content was being interpreted as an object rather than the string it actually was, so IE couldn't render the page.

It now renders the index, but Angular-UI-Router doesn't seem to work.

It appears as though ui-router can't load sub states (it can switch between normal states though, since I was able to log in and be transferred to my dashboard page, which is a different state)

(Everything is still working perfectly fine on Chrome and Firefox)

回答1:

Could it be sending you a file because you're using .sendFile():

app.get('/', function(req, res){
    sendFile(res, './index.html', getHeader('text/plain'));
});

instead of using .render() to render the page?

app.get('/', function (req, res) {
  res.render('index.html');
})


回答2:

Try using Express's use() to always send via sendFile() the index.html after any HTTP action using the * wildcard. Make sure this goes after any other API REST routes or similar. This helps ensure that the Angular app within index.html is not constantly reloaded by other pages being rendered. This way any other API routes send/receive the data you need and only if nothing else is matched, will the index.html be loaded. Below is a structure that worked for me for an Express + Angular 2 application.

File Structure:

api
    foo
        foo.js
    bar
        bar.js
public
    fonts
    css
    img
    index.html
server.js

Server JS:

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

// fonts, css, images are stored in respective folders within folder "public"
app.use(express.static(path.join(__dirname, 'public')));

// some RESTful endpoints
app.use('/api/foo', fooRoutes);
app.use('/api/bar', barRoutes);

app.use('*', (req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));

// error handling middleware
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});