2014-01-08 22 views
10

您已经创建了一个与yeoman,grunt和bower的angularJS应用程序。 我已经为应用程序启用了html5Mode。它的工作。但是,当我刷新页面(本地主机:9000 /登录),它说AngularJS - html5mode - 无法获取/登录

Cannot GET /login //or any url I type or refresh 

这里是应用程序的结构

MainApp 
| 
|__app 
| | 
| |__bower_components 
| | 
| |__scripts 
| | | 
| | |__ app.js 
| | | 
| | |__contollers -- login.js, home.js, register.js 
| | | 
| | |__service -- js files 
| | | 
| | |__styles -- CSS files 
| | | 
| | |__views -- main.html, login.html, register.html,home.html 
| | 
| |__ index.html 
| 
|__ node_modules 
| 
|__ bower.json, Gruntfile.js, karma-conf.js, karma-e2e.conf.js, package.json 

这里是我的app.js路由

'use strict';  
var superClientApp=angular.module('mainApp', ['ngCookies']); 

//Define Routing for app 
superClientApp.config(['$routeProvider', '$locationProvider', 
    function($routeProvider,$locationProvider) { 
    $routeProvider 
    .when('/login', { 
     templateUrl: 'login.html', 
     controller: 'LoginController' 
    }) 
    .when('/register', { 
     templateUrl: 'register.html', 
     controller: 'RegisterController' 
     }) 
    .when('/home', { 
     templateUrl: 'views/home.html', 
     controller: 'homeController' 
    }) 
    .otherwise({ 
     redirectTo: '/login' 
    }); 
    $locationProvider.html5Mode(true); 
}]); 

这是我的一部分Gruntfile.js

'use strict'; 
var LIVERELOAD_PORT = 35729; 
var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); 
var mountFolder = function (connect, dir) { 
    return connect.static(require('path').resolve(dir)); 
}; 
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest; 

// # Globbing 
// for performance reasons we're only matching one level down: 
// 'test/spec/{,*/}*.js' 
// use this if you want to recursively match all subfolders: 
// 'test/spec/**/*.js' 

module.exports = function (grunt) { 
    require('load-grunt-tasks')(grunt); 
    require('time-grunt')(grunt); 

    // configurable paths 
    var yeomanConfig = { 
    app: 'app', 
    dist: 'dist' 
    }; 

    try { 
    yeomanConfig.app = require('./bower.json').appPath || yeomanConfig.app; 
    } catch (e) {} 

    grunt.initConfig({ 
    yeoman: yeomanConfig, 
    watch: { 
     coffee: { 
     files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'], 
     tasks: ['coffee:dist'] 
     }, 
     coffeeTest: { 
     files: ['test/spec/{,*/}*.coffee'], 
     tasks: ['coffee:test'] 
     }, 
     styles: { 
     files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 
     tasks: ['copy:styles', 'autoprefixer'] 
     }, 
     livereload: { 
     options: { 
      livereload: LIVERELOAD_PORT 
     }, 
     files: [ 
      '<%= yeoman.app %>/{,*/}*.html', 
      '.tmp/styles/{,*/}*.css', 
      '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', 
      '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 
     ] 
     } 
    }, 
    autoprefixer: { 
     options: ['last 1 version'], 
     dist: { 
     files: [{ 
      expand: true, 
      cwd: '.tmp/styles/', 
      src: '{,*/}*.css', 
      dest: '.tmp/styles/' 
     }] 
     } 
    }, 
    connect: { 
     options: { 
     port: 9000, 
     // Change this to '0.0.0.0' to access the server from outside. 
     hostname: 'localhost' 
     }, 
     proxies: [ 
     { 
      context: '/serverApp', 
      host: 'localhost', 
      port: '8080', 
      https: false, 
      changeOrigin: false 
     } 
     ], 
     livereload: { 
     options: { 
      middleware: function (connect) { 
      return [ 
       lrSnippet, 
       proxySnippet, 
       mountFolder(connect, '.tmp'), 
       mountFolder(connect, yeomanConfig.app) 
      ]; 
      } 
     } 
     }, 

我已经通过this SO question。并基于accepted answer,我将我的Gruntfile.js更改为以下。

'use strict'; 
var LIVERELOAD_PORT = 35729; 
var lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT }); 
var mountFolder = function (connect, dir) { 
    return connect.static(require('path').resolve(dir)); 
}; 
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest; 

var urlRewrite = require('grunt-connect-rewrite'); 

// # Globbing 
// for performance reasons we're only matching one level down: 
// 'test/spec/{,*/}*.js' 
// use this if you want to recursively match all subfolders: 
// 'test/spec/**/*.js' 

module.exports = function (grunt) { 
    require('load-grunt-tasks')(grunt); 
    require('time-grunt')(grunt); 

    // configurable paths 
    var yeomanConfig = { 
    app: 'app', 
    dist: 'dist' 
    }; 

    try { 
    yeomanConfig.app = require('./bower.json').appPath || yeomanConfig.app; 
    } catch (e) {} 

    grunt.initConfig({ 
    yeoman: yeomanConfig, 
    watch: { 
     coffee: { 
     files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'], 
     tasks: ['coffee:dist'] 
     }, 
     coffeeTest: { 
     files: ['test/spec/{,*/}*.coffee'], 
     tasks: ['coffee:test'] 
     }, 
     styles: { 
     files: ['<%= yeoman.app %>/styles/{,*/}*.css'], 
     tasks: ['copy:styles', 'autoprefixer'] 
     }, 
     livereload: { 
     options: { 
      livereload: LIVERELOAD_PORT 
     }, 
     files: [ 
      '<%= yeoman.app %>/{,*/}*.html', 
      '.tmp/styles/{,*/}*.css', 
      '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', 
      '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 
     ] 
     } 
    }, 
    autoprefixer: { 
     options: ['last 1 version'], 
     dist: { 
     files: [{ 
      expand: true, 
      cwd: '.tmp/styles/', 
      src: '{,*/}*.css', 
      dest: '.tmp/styles/' 
     }] 
     } 
    }, 
    connect: { 
     options: { 
     port: 9000, 
     // Change this to '0.0.0.0' to access the server from outside. 
     hostname: 'localhost', 
     base: 'app', 
     middleware: function(connect, options) { 
      // Return array of whatever middlewares you want 
      return [ 
       // redirect all urls to index.html in build folder 
       urlRewrite('app', 'index.html'), 

       // Serve static files. 
       connect.static(options.base), 

       // Make empty directories browsable. 
       connect.directory(options.base) 
      ]; 
      } 
     }, 
     proxies: [ 
     { 
      context: '/serverApp', 
      host: 'localhost', 
      port: '8080', 
      https: false, 
      changeOrigin: false 
     } 
     ], 
     livereload: { 
     options: { 
      middleware: function (connect) { 
      return [ 
       lrSnippet, 
       proxySnippet, 
       mountFolder(connect, '.tmp'), 
       mountFolder(connect, yeomanConfig.app) 
      ]; 
      } 
     } 
     }, 

但是当我刷新页面时仍然出现同样的错误。如何解决这个问题?

+1

本地主机后加入server.js这个代码? – michael

+0

对不起,我没有得到你 –

+2

在纯HTML5模式,你不能直接调用网址。您首先需要调用localhost:9000,以便浏览器可以配置此模式。之后,在href =“login”上点击将包含你想要的模板。 – michael

回答

4

你必须有一个服务器端解决方案,以重定向所有非解决流量的index.html

我将分享一个htaccess这个版本和一个node.js版本。我也在春季启动中实现了这一点,但是这涉及更多一点。

的.htaccess

<IfModule mod_rewrite.c> 
    RewriteEngine On 
    RewriteBase /the-base-from-index.html/ 


    RewriteEngine on 
    RewriteCond %{HTTP:X-Requested-With} !XMLHttpRequest$ 
    RewriteCond %{REQUEST_FILENAME} !-f 
    RewriteRule . index.html [L] 
</IfModule> 

为了这个工作你的Apache配置必须启用mod_rewrite的,也允许覆盖所有。重写也将在Apache配置中工作。

还有一个条件,允许您在ajax请求上返回404。为了实现这个目标,你必须为所有的$ http请求注册一个pre-flight头文件,表明它们是xmlhttp请求。是这样的:

myapp.config(function($httpProvider) { 
     $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; 
}); 

的NodeJS

var express = require('express'); 
var bodyParser = require('body-parser') 
var path = require('path') 
var app = express(); 

app.use(express.static(__dirname + '/app')); 
app.get('/*', function(req, res){ 
    res.sendFile(__dirname + '/app/index.html'); 
}); 

app.listen(9090); 
console.log("Node Server Listening on port 9090"); 

这是污垢简单,而且可以改善。即对xmlhttp头的req头进行检查,类似于htaccess示例正在做的事情。

这些得到了大致的想法。基本上任何会导致404获得服务的流量index.html。这允许您继续提供静态内容,但是您的路由(只要它们不在该位置的磁盘上实际存在)将返回index.html。

警告!如果没有像所有ajax请求中的预检标题这样的解决方案,任何未解决的模板请求都将导致无限循环并可能锁定您的浏览器。 !9000 /#/登录:

-1

你尝试过使用绝对路径在$routeProvider

.when('/login', { 
    templateUrl: '../app/scripts/views/login.html', 
    controller: 'loginController' 
}, 
... 
0

这是发生,因为当你按刷新,浏览器将尝试从服务器检索/登录,而不是通过您的客户端路线提供商。我认为/ login在你的情况下返回404。

即使请求是为/ login生成的,您需要获取实际上为您的文件提供/index.html服务的服务器。你如何做到这一点取决于你的服务器端设置。你可以用动态脚本或重写规则来做到这一点。

如果你不能用这种方式控制服务器,那么htmlmode可能不适合你。

+1

我只使用Grunt。我如何在Gruntfile.js中执行重写规则? –

2

到目前为止,Angular需要处理路由才能工作的问题。

我发现了这样类似的问题,这表明同一HTML5 config来解决该hashbang方法 - 看AngularJS: how to enable $locationProvider.html5Mode with deeplinking 此外,在scotch.io https://scotch.io/quick-tips/pretty-urls-in-angularjs-removing-the-hashtag教程可以是一个开始。

但最重要的是,我记得这是一个伎俩。

https://gist.github.com/leocaseiro/4305e06948aa97e77c93

我运行的Apache Web服务器。我不记得在什么级别(全局或每个应用程序)我做了配置,但最好是咨询Web服务器文档,Apache的很好。

0

加入侧“的意见/ login.html的”你templateUrl希望这将工作

0

所有路由

app.use('/*',function(req, res) { 
    res.sendfile(__dirname + '/public/index.html'); 
});