Laravel 5 redirect()->back() 无法按预期工作


Laravel 5 redirect()->back() doesn't work as expected

当没有设置HTTP_REFERER时,我在redirect()->back()时遇到了问题。

通常,当我打开带有ID作为参数的URL以显示特定数据行时: http://my-domain/module/ID

如果指定的ID不存在或当前登录用户没有打开它的权限,我使

if (!$this->checkPermission($id)) {
    return redirect()->back()->withError('message');
}
// do my stuff to show the datarow

但是当我更改浏览器地址字段并加载不允许的ID时,没有设置HTTP_REFERERredirect()->back()将我重定向到上次加载的 JavaScript for_this_view.js(并显示它(添加到视图中,如下所示:

应用刀片.php

<!DOCTYPE html>
<html lang="de">
<head>
    @section('head')
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {!! HTML::style('assets/jquery-ui/jquery-ui.min.css?ver=1.11.4') !!}
    <!-- some more scripts -->
    @show
</head>
<body>
    @yield('content')
</body>
</html>

秀刀锋.php

@extends('app')
@section('head')
    @parent
    {!! HTML::script('for_this_view.js') !!}
@stop
@section('content')
    <!-- display datarow -->
@stop

redirect()->back()在这里做什么?如果没有 URL 重定向回 laravel是在猜测吗?为什么呢?也许永远有办法重定向。

这使我无法使用此功能。

更新

啊,也许我找到了我的问题...

我尝试动态加载JavaScript,如果它们存在于特定文件夹中。我这样做是因为我希望我的JavaScript像视图一样解析,以便在其中获取刀片语法。我在/config/view.php中添加了一个特定的文件夹并制作了类似 for_this_view_js.blade.php 的文件。它们作为for_this_view.js动态添加到routes.php中。

因此,我做了这样的事情:

/* load view javascripts */
/** @var 'SplFileInfo $path */
foreach (new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator(public_path())
    ) as $path)
{
    if ($path->isFile()
        && ends_with($path->getFilename(), 'js.blade.php'))
    {
        Route::get('url_to_javascript.js', function() {
            $contents = View::make('for_this_view_js(.blade.php)');
            $response = Response::make($contents);
            $response->header('Content-Type', 'application/javascript');
            return $response;
        });
    }
}

如果未设置HTTP_REFERER,Laravel将尝试从会话获取最后一个请求。此网址存储在Illuminate'Session'Middleware'StartSession

protected function storeCurrentUrl(Request $request, $session)
{
    if ($request->method() === 'GET' && $request->route() && ! $request->ajax())
    {
        $session->setPreviousUrl($request->fullUrl());
    }
}

如您所见,有几个条件,不幸的是,您的JS请求满足了这些条件:

  1. 获取方法
  2. 由路由处理
  3. 不是 ajax 请求

溶液

在我看来,你有两个选择。

禁用中间件

警告:我还没有测试过这个,可能会有副作用

转到app/Http/Kernel.php并从$middleware中删除'Illuminate'Session'Middleware'StartSession',。现在,如果没有设置HTTP_REFERER,Laravel将简单地重定向到应用程序的根目录(/(

扩展中间件并添加其他约束

您可以扩展中间件并添加一些额外的检查:

class CustomStartSession extends 'Illuminate'Session'Middleware'StartSession {
    public function storeCurrentUrl(Request $request, $session){
        if(!ends_with($request->url(), '.js')){
            parent::storeCurrentUrl($request, $session);
        }
    }
}

然后通过将 app/Http/Kernel.php 中的原始StartSession替换为您的来启用它,任何 URL 以 .js 结尾的请求都不会保存为"以前的 URL">

更新

显然,中间件需要注册为单例才能完全正常运行。您可以通过将其添加到您的服务提供商之一的register方法中来做到这一点(例如 AppServiceProvider (

$this->app->singleton('App'Http'Middleware'CustomStartSession');

我目前的解决方法是像这样扩展BaseController

<?php namespace App'Http'Controllers;
use Illuminate'Foundation'Bus'DispatchesCommands;
use Illuminate'Routing'Controller as BaseController;
use Illuminate'Foundation'Validation'ValidatesRequests;
abstract class Controller extends BaseController
{
    use DispatchesCommands, ValidatesRequests;
    /**
     * The fallback url for redirects...
     * Prevent faulty redirect if 'HTTP_REFERER' not set.
     *
     * @var string
     */
    private static $back_url = '';
    /**
     * @param string $back_url The fallback url for redirects...
     */
    public static function setBackUrl($back_url)
    {
        self::$back_url = $back_url;
    }
    /**
     * @return string
     */
    protected static function getBackUrl()
    {
        return self::$back_url;
    }
    /**
     * @return 'Illuminate'Http'RedirectResponse
     */
    public static function redirect_back()
    {
        $back = self::getBackUrl();
        if (!empty($_SERVER['HTTP_REFERER']))
        {
            return redirect()->back();
        } else if (!empty($back)) {
            return redirect()->to($back);
        } else {
            return redirect()->to('/');
        }
    }
}

然后这样称呼它:

<?php namespace App'Http'Controllers;
use App'Http'Requests;
use App'Http'Controllers'Controller;
/**
 * Class MyController
 *
 * @package App'Http'Controllers
 */
class MyController extends Controller
{
    /**
     * Check permission for specified '$id'.
     *
     * @param int|string $id The datarow id
     * @return boolean
     */
    public function checkPermission($id)
    {...}
    /**
     * Display a listing of the resource.
     *
     * @param int|string $id The datarow id
     * @return Response
     */
    public function index($id)
    {
        if (!$this->checkPermission($id)) {
            self::setBackUrl('URL::route('my_prefered_fallback_route'));
            return self::redirect_back()
                ->withErrors(["message"]);
        }
        return 'Hello, API';
    }
}
我知道

这很丑陋,但您可以通过在控制器中将请求方法更改为 POST 来避免 storeCurrentUrl((。

$request->setMethod('POST');