将 AngularJS html5mode 与 nodeJS 和 Express 一起使用

Posted

技术标签:

【中文标题】将 AngularJS html5mode 与 nodeJS 和 Express 一起使用【英文标题】:using AngularJS html5mode with nodeJS and Express 【发布时间】:2013-07-21 23:21:57 【问题描述】:

我正在使用带有 Express 的 nodeJS 服务器来为我的 AngularJS 应用程序提供服务。当我使用 angularJS 默认路由(hashbangs)时,这一切都很好,但现在我正在尝试激活 html5 模式。

我正在像这样激活 html5mode:

$locationProvider.html5Mode(true).hashPrefix('!');

这就是我的 nodeJS app.js 文件的样子:

var path     = require('path'),
    express  = require('express'),
    app      = express(),
    routes   = require(path.join(__dirname, 'routes'));

app.configure(function() 
    app.use(express.logger('dev'));
    app.use(express.compress());
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
    app.all("/*", function(req, res, next) 
        res.sendfile("index.html",  root: __dirname + "/../app" );
    );
    app.use(express.errorHandler(
        dumpExceptions: true, 
        showStack: true
    ));
);

但是,现在这会将所有请求作为我的 index.html 文件提供,因此我从 requireJS 收到以下错误:

Uncaught SyntaxError: Unexpected token < 

我尝试将以下内容添加到我的 nodeJS app.js,以便它可以正确地为我的资源提供服务:

app.use("/js", express.static(__dirname + "/../app/js"));
app.use("/img", express.static(__dirname + "/../app/img"));
app.use("/css", express.static(__dirname + "/../app/css"));
app.use("/partials", express.static(__dirname + "/../app/partials"));

但仍然没有运气。

我还尝试将 app.all 语句替换为:

app.use(function(req, res) 
  // Use res.sendfile, as it streams instead of reading the file into memory.
  res.sendfile(__dirname + '/../app/index.html');
);

但这也没有用。我该怎么做才能让 angularJS html5mode 与 nodeJS 和 Express 一起工作?谢谢。

【问题讨论】:

您可能看到了Uncaught SyntaxError: Unexpected token &lt; ,因为未按预期找到路径。不是返回您想要的 javascript(或 CSS 等)文件,而是触发“catch all /*”路由并返回 HTML。 应用没有“配置”方法 Uncaught SyntaxError: Unexpected token &lt; 是由于您的 Angular js 应用程序文件未加载而引起的。检查到您的 js 目录的路由。您可能希望将它们从 / 更改为 /public 或其他比 / 更独特的名称 【参考方案1】:

您的初始修复(为特定前缀声明静态中间件处理程序)应该可以正常工作,但您需要确保在任何其他路由之前声明它们(以及app.router,尽管您没有不需要显式使用它):

// these need to go first:
app.use("/js", express.static(__dirname + "/../app/js"));
app.use("/img", express.static(__dirname + "/../app/img"));
app.use("/css", express.static(__dirname + "/../app/css"));
app.use("/partials", express.static(__dirname + "/../app/partials"));

// any other routes:
app.all("/*", ...);

另外,您需要确保前缀静态处理程序实际上被声明为正常(正确的路径),否则它们将无法找到任何请求的文件,并且请求将传递到中间件链并最终由catch-all 处理程序(应该很容易通过注释掉 catch-all 处理程序并查看任何 JS/CSS/... 请求是否正常进行测试)。

【讨论】:

没错,如果你使用像 nginx 这样的代理服务器,那么你不妨在代理级别设置依赖路由【参考方案2】:

像这样配置 express 4 服务器:

app.use(express.static(__dirname + '/public'));

app.get('/*', function(req, res)
    res.sendFile(__dirname + '/public/index.html');
);

和角度类似:

app.config(function($stateProvider, $urlRouterProvider, $locationProvider)
    $stateProvider
        .state('home', 
            url: '/',
            templateUrl: 'templates/main.html'
        )
        .state('register', 
            url: '/register',
            templateUrl: 'templates/register.html'
        );

    $urlRouterProvider.otherwise("/");
    $locationProvider.html5Mode(
        enabled: true,
        requireBase: false
    );
);

【讨论】:

【参考方案3】:

我正在开发一个 Web 应用程序,在客户端使用 Angularjs 和 Requirejs,在服务器上使用 Nodejs。

这里是一些示例代码,向您展示我是如何设置它的。

请注意,此示例显示的是哈希 url,但您可以通过修改中间件函数和角度配置轻松更改它

中间件函数

isXHR: function (req, res, next) 
    if (req.xhr || req.get("angular-request") === "ajaxRequest") 
        next();
     else 
        var url = req.url;
        var urls = url.split("/");
        var last = _.last(urls);
        urls = _.without(urls, last);
        url = urls.join("/") + "#/" + last //remove the hash if you want to make it html5mode;

        res.redirect(url);
    

服务器路由配置

//I'm using express-namespace to group my routes
app.namespace("/requirements", function()
   //Shared local variable used across the application
   var info = 
        app: 
            title: "Requirements",
            module: "app/requirements" // where the angular application stored
        
    
    //this is the main url that will user request
    Route.get("/", function (req, res) 
        res.cookie("profileRegisterationSteps", 0);
        res.render("app/requirements/index", info);
    );
   //this is the url angular js will request
    Route.get("type", filters.isXHR, function (req, res) 
        res.render("app/requirements/profile/type", info);
    );
 )

客户端路由配置

require(['App', 'underscore', 'ngAmd'/*angular amd*/, 'autoload'/*No Sense*/, 'appLoader' /*i used to load my scripts file for the route user requested (not all scripts files only who requested) before template laoded*/, 'appRoute'/*this is a list of routes*/], function (app, _, amd, autoload, loader, routes) 

app.config(function ($routeProvider, $locationProvider, $httpProvider) 
    //remove a clearn URL
    $locationProvider.html5Mode(false);

    //ku dar header kan si uu server ka u ogaado Request in yahay Ajax
    $httpProvider.defaults.headers.common['angular-request'] = "ajaxRequest";

    //Route Config
    var Route = $routeProvider;
    //get all routes objects that defined in routes module
    _.each(routes, function (route) 
        // extend the routes module objects and use its properties
        Route.when(route.url, _.extend(route, 
            //call returning function in loader module and write the promise
            resolve: _.extend(loader(route))
        ));
    );
    Route.otherwise(
        redirectTo: "/"
    );

);

  //start the application
  amd.bootstrap(app);
 );

应用程序文件

require.config(
    paths: 
        //pages
       type: "Apps/requirements/pages/type"
   
);
 define(['App'], function(app) 
    return function (options) 
      return 
        loader: function ($q, $rootScope) 
            var defer = $q.defer();
            var module = options.name// the name of the route (this name corresponds to the requirejs module name above;

            if (!!(module)) 
                if (require.defined(module)) 
                    defer.resolve();
                 else 
                    require([module], function () 
                        $rootScope.safeApply(function () 
                            defer.resolve();
                        )
                    );
                
             else 
                defer.resolve();
            

            return defer.promise;
        
      
    
 );

路由文件

define(function()
  return 
     
        name        : "type",
        url         : "/",
        templateUrl : "/requirements/type",
        view        : 'services'
    

 

)

【讨论】:

以上是关于将 AngularJS html5mode 与 nodeJS 和 Express 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 HTML5Mode 配置多个 AngularJS2 项目的 Nginx 配置

html5Mode中的Angularjs链接问题[重复]

AngularJS - ui-router - MVC 5 - html5mode

Laravel 5 + AngularJS html5Mode

ini AngularJS Nginx和html5Mode

ini AngularJS Nginx和html5Mode