HTML5模式下,AngularJS和Laravel 4路由冲突

9
我希望使用Angularjs的$locationProvider.html5Mode(true)来从URL中移除#哈希。
例如:地址栏显示http://localhost/shop而不是http://localhost/#/shop
一切都运作良好,直到我刷新页面。如果我刷新,将访问以下在routes.php中定义的Laravel路由。
Route::resource('shop', 'ShoppingController')

不是AngularJS Route(在app.js中定义)

$routeProvider.when('/shop', { 
    templateUrl: 'templates/shop.html', 
    controller: 'ShoppingController' 
});

我的代码:

routes.php (Laravel 路由)

Route::get('/', function() {
    return View::make('index'); 
});
Route::resource('shop', 'ShoppingController'); 

app.js(AngularJS路由)


var app = angular.module('shoppingApp',['ngRoute','SharedServices']); 

app.config(function($routeProvider, $locationProvider) { 
    $routeProvider.when('/shop', {
        templateUrl: 'templates/shop.html', 
        controller: 'ShoppingController'
    });
    $routeProvider.otherwise({ redirectTo: '/' }); 
    $locationProvider.html5Mode(true); 
});

我的目录结构:

Project
    /app 
        /...
        /views
            -index.php (single page application file)
            -routes.php (Laravel routes)
    /public
        /...
        /js
            -angular.js
            -app.js
        -index.php (Laravel index file)

已尝试的解决方案:

重写htaccess文件,使所有请求都重定向到index.php(单页应用程序文件,从这里AngularJS将接管路由)。 问题:通过这种方式,Laravel路由(Route :: resource('shop','ShoppingController'); - 与数据库交互所必需的)对于AngularJS $http服务变得不可访问:

app.js

app.controller("ShoppingController", function($scope, $http) {
    $http.get('/shop', { cache: true}).
        success(function(data, status) {
        $scope.items = data
    }).
    error(function(data, status) {
        console.log('Status: ' + status);
        });
});

问题: 如何解决路由问题,使得在刷新 localhost/shop 时访问的是 AngularJS 路由而非 Laravel 路由?

6个回答

7
根据我所阅读的,刷新页面时Laravel好像会读取修改后的路由。在这种情况下,即使原本会进行404重定向,你也应该让Laravel继续使用原始视图。尝试在Laravel端的某个地方(如routes.php)添加以下内容。
App::missing(function($exception)
{
    return View::make('index');
});

注意: 你可能希望使用AngularJS的路由来处理找不到的页面, 使用 .otherwise。


1
感谢您的回复。我按照这个优秀的教程(http://scotch.io/tutorials/php/create-a-laravel-and-angular-single-page-comment-application)的建议,添加了一个catch all路由,并为所有后端路由添加了前缀(Route::group(array('prefix' => 'api'), function(){}) )。 - user1894374
我认为这将避免404错误页面。因此,我们的应用程序将不会有任何404页面! - نرم افزار حضور و غیاب

5
更好的解决方案是这样重定向:

'Redirect::to('/#/' . Request::path())'

当你刷新或直接访问URI时:

  • 'Request::path()':返回请求的URI,即('/shop/categories/electronics');
  • 在HTML5模式下的AngularJS仍然响应'#/'前缀;
  • 如果AngularJS检测到HTML5模式中的前缀,它将自动为您删除该前缀。

最终解决方案:

App::missing(function($exception) {
    return Redirect::to('/#/' . Request::path());
});

3
如果您正在使用Laravel 5,则请前往app/Exception/Handler.php并放置以下代码:
public function render($request, Exception $e)
{
    if($e instanceof NotFoundHttpException)
    {
        return Redirect::to('/#/' . Request::path());
    }
    return parent::render($request, $e);
}

0
对于 Laravel 4.x 或 5.x,我使用这个简单而好用的技巧,无需更改 .htaccess 文件。这个技巧非常简单,对我很有效。它不会重定向 URL,用户在刷新页面时仍然停留在相同的 URL 上,并且页面将被刷新:
Route::get('dashboard/{all?}', function(){
    return view('main.index');
});

这里我的仪表板应用是单页应用程序。这样我们也可以解决404错误页面。


0

我有另一种解决方案,我发现它非常有用。与其只是创建主页视图,我将URI传递到主页,由控制器进行检查并相应地重定向(Angular方式)。这意味着,如果您在myapp.com/about上,并刷新页面,它不会带您回到主页,而是带您回到当前所在的页面。

routes.php:请注意,我有一个URI通配符,将其作为回调函数的参数传递,然后作为变量传递给视图。

// Note that this must be on the bottom of your routes file because
// if you have any registered route with a similar pattern
// it will get caught by this route and never reach any registered routes you might have
Route::get('{slug}', function($slug){
    return View::make('index', compact('slug'));
});


// These routes will never get hit, so move them above Route::get('{slug}')
Route::get('about', function(){...});
Route::get('contact', function(){...});

index.blade.php:

<html ng-app"myApp">
<head>
    ...
</head>
<body>
    <!--Check if there is a variable named $slug that is set-->
    <!--If it is, set hidden input with ng-model-->
    @if(isset($slug))
        <input type="hidden" value="{{slug}}" ng-model="slug" ng-controller="RedirectController">
    @endif

    <div ng-view></div>
</body>
</html>

app.js

angular.module('myApp', [])
    .controller('RedirectController', ['$location', '$scope', function ($location, $scope) {
        // If slug is set, redirect to that slug
        if ($scope.slug) {
            $location.path('/' + $scope.slug);
        }
    }]);

0
如果您想在html5mode下运行多个单页面应用程序,或者只是在Laravel应用程序中有其他用途的App :: missing,那么您可以使用类似于以下的重写规则:
#Redirect base url of AngularJS app in html5mode

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/path/.+$
RewriteRule  ^(path)/(.*)  /path/#/$2           [R=301,L,NE]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接