【问题标题】:Laravel 5 + AngularJS Cross Domain CORSLaravel 5 + AngularJS 跨域 CORS
【发布时间】:2015-05-16 17:06:54
【问题描述】:

我到处寻找答案,但到目前为止没有任何效果。堆栈上列出的所有解决方案都没有被证明是足够的。

我的 laravel 日志中没有任何错误形式,我只得到标准:

XMLHttpRequest cannot load http://api.domain.dev/post/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://domain.dev' is therefore not allowed access.

Laravel 控制器:

<?php namespace App\Http\Controllers;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Post;
use App\Tag;
use Illuminate\Http\Request;

class PostController extends Controller {

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {

        $posts = Post::with('user', 'tags')->get();

        return response()->json($posts);
    }
}

Laravel 路由:

<?php

Route::resource('user', 'UserController');
Route::resource('post', 'PostController');
Route::get('post/tag/{tag}', 'PostController@postsWithTag');
Route::resource('tag', 'TagController');

Route::controllers([
    'auth' => 'Auth\AuthController',
    'password' => 'Auth\PasswordController',
]);

有点臃肿没有组织的角度:

//App
var app = angular.module('app', [
    'ngRoute',
    'ngAnimate'
    ]);

//Config
app.config(['$routeProvider', '$locationProvider', '$animateProvider', function($routeProvider, $locationProvider, $animateProvider) {

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

    $routeProvider.
    when('/', {
        templateUrl: 'partials/home.html',
        controller: 'PageController'
    }).
    when('/about', {
        templateUrl: 'partials/about.html',
        controller: 'AboutController'
    }).
    when('/contact', {
        templateUrl: 'partials/contact.html',
        controller: 'ContactController'
    }).
    when('/blog', {
        templateUrl: 'partials/blog.html',
        controller: 'PostsController'
    }).
    when('/blog/post/:postId', {
        templateUrl: 'partials/post.html',
        controller: 'PostController'
    }).
    otherwise({
        redirectTo: '/'
    });


}]);

//Factory
app.factory('Data', function Data($http) {

    return {
        getPosts: function getPosts() { return $http.get('http://api.domain.dev/post/'); },
        getPost: function getPost(id) { return $http.get('http://api.domain.dev/post/' + id); },
        addPost: function addPost(data) { return $http.post('http://api.domain.dev/post/', data); },
        removePost: function removePost(id) { return $http.delete('http://api.domain.dev/post/'+ id); },

        getTags: function getTags() { return $http.get('http://api.domain.dev/tag/'); },
        getTag: function getTag(id) { return $http.get('http://api.domain.dev/tag/' + id); },
        addTag: function addTag(data) { return $http.post('http://api.domain.dev/tag/', data); },
        removeTag: function removeTag(id) { return $http.delete('http://api.domain.dev/tag/'+ id); },

    } 
}); 

//Posts Controller
app.controller('PostsController', function PostsController($scope, Data) {



    Data.getPosts().success(parsePosts);

    function parsePosts(data) { 
        $scope.posts = data; 
    }

    //AddPost
    $scope.newPost = { title: '', content: '', resume: '' };

    $scope.addPost = function addPost(){Data.addPost({ title: $scope.newPost.title, content: $scope.newPost.content, resume: $scope.newPost.resume, user_id: $scope.newPost.user_id }).success(postAddSuccess).error(postAddError);}

    function postAddSuccess(data) {
        $scope.error = null;
        $scope.posts.push(data);
        $scope.newPost = { title: '', content: '', resume: '' }; 
    }

    function postAddError(data) { 
        $scope.error = data; 
    }

    //RemovePost
    $scope.removePost = function removePost(id) {
        if (confirm('Do you really want to remove this post?')) {
            Data.removePost(id).success(postRemoveSuccess); 
        } 
    }

    function postRemoveSuccess(data) {
        var i = $scope.posts.length;
        while (i--) {
            if ($scope.posts[i].id == data) {
                $scope.post.splice(i, 1);
            }
        }
    }

});

//Post Controller
app.controller('PostController', function PostController($scope, $routeParams, Data) {
    Data.getPost($routeParams.id).success(parsePost);

    function parsePost(data) {
        $scope.post = data;
    }

    Data.getTags($routeParams.id).success(parsePostsTags);

    function parsePostsTags(data) {
        $scope.tags = data;
    }

    $scope.newTag = { tag: '' };

    $scope.addTag = function addTag() {
        $scope.newTag.post_id = $scope.post.id;
        Data.addTag($scope.newTag).success(tagAddSuccess).error(tagAddError);
    }

    function tagAddSuccess(data) {
        $scope.error = null;
        $scope.tags.push(data);

        $scope.newTag = { tag: '' };
    }

    function tagAddError(data) {
        $scope.error = data;
    }

    $scope.removeTag = function removeTag(id) {
        if (confirm('Do you really want to remove this tag?')) {
            Data.removeTag(id).success(tagRemoveSuccess);
        }
    }

    function tagRemoveSuccess(data) {
        var i = $scope.tags.length;
        while (i--) {
            if ($scope.tags[i].id == data) {
                $scope.tags.splice(i, 1);
            }
        }
    }
});

//About Controller
app.controller('AboutController', function AboutController($scope, Data) {



});

//Portfolio Controller
app.controller('PortfolioController', function PortfolioController($scope, Data) {



});

//Contact Controller
app.controller('ContactController', function ContactController($scope, Data) {



});

//Page Controller
app.controller('PageController', function PageController($scope, Data) {



});

我不知道从这里去哪里。 我已经尝试了从普通的header() 实现到使用 laravel-cors 包通过过滤器和控制器中的 _construct 实现的所有方法。 我也去了服务器配置路线,并尝试将标头添加到 .htaccess 和虚拟主机配置。

【问题讨论】:

标签: angularjs cors laravel-5


【解决方案1】:

在返回header("Access-Control-Allow-Origin: *");之前添加这一行

你的代码应该是

public function index()
{
    $posts = Post::with('user', 'tags')->get();
    header("Access-Control-Allow-Origin: *");
    return response()->json($posts);
}

【讨论】:

  • 我知道你在做什么,但除了在 chrome 控制台中返回相同的错误之外什么也没做。
  • @user2298680 我遇到了同样的问题。但是我通过 header("Access-Control-Allow-Origin: *"); 解决了这个问题...让我们看看有人会解决你的问题。
  • 当 angular.js 应用程序从其他域登录时,我的 Laravel 5.0 API 正在失去会话。这些 angular.js 应用程序托管在其他域、其他服务器中。
【解决方案2】:

我对 laravel 没有很好的了解。但是我的建议是请求标头访问 REST 方法(GET、POST、PUT、DELTE)和来源到特定域,您可以通过以下方式或从哪个域发出请求否则设置为'*'(它允许任何域)

header('Access-Control-Allow-Origin', 'some url');
header('Allow', 'GET, POST, OPTIONS');
header('Access-Control-Allow-Headers', 'Origin, Content-Type, Accept, Authorization, X-Request-With');
header('Access-Control-Allow-Credentials', 'true');

在 Angular js。如果您使用

myApp.config(['$httpProvider', function($httpProvider) {
            $httpProvider.defaults.useXDomain = true;
            delete $httpProvider.defaults.headers.common['X-Requested-With'];
        }
    ]);

【讨论】:

    【解决方案3】:

    当您调用跨源 XHR 请求时,javascript 首先会向给定 URL 触发 OPTIONS 请求。如果这个方法没有添加到你的路由中,那么它会弹出一个没有 ACAO 标头的 404 页面,因此不会发送具体的 POST 请求,因为 javascript 认为它不允许。

    【讨论】:

      【解决方案4】:

      添加

      <?php header("Access-Control-Allow-Origin: *"); ?>
      

      如果它在蓝铃建议的功能中不起作用,则到 public/index.php

      【讨论】:

        【解决方案5】:

        在您的 public/index.php 中添加这些行:

        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token'); // allow certain headers 
        

        看看,是否可行。

        【讨论】:

          【解决方案6】:

          我遇到了同样的问题,但使用 jQuery 并花了我数周时间才找到一个好的解决方案。

          我的情况是创建一个中间件来设置标题是完美的解决方案。

          创建一个 Cors 中间件:App\Http\Middleware\Cors.php

          namespace App\Http\Middleware;
          
          use Closure;
          
          class Cors
          {
          
              /**
               * Handle an incoming request.
               *
               * @param  \Illuminate\Http\Request $request
               * @param  \Closure $next
               *
               * @return mixed
               */
              public function handle($request, Closure $next)
              {
                  return $next($request)
                      ->header('Access-Control-Allow-Origin', $_SERVER['HTTP_ORIGIN'])
                      // Depending of your application you can't use '*'
                      // Some security CORS concerns 
                      //->header('Access-Control-Allow-Origin', '*')
                      ->header('Access-Control-Allow-Methods', 'POST, OPTIONS')
                      ->header('Access-Control-Allow-Credentials', 'true')
                      ->header('Access-Control-Max-Age', '10000')
                      ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
              }
          }
          

          记得在 App\Http\Kernel 中设置 Cors 别名

          protected $routeMiddleware = [
              ...
              'cors' => \App\Http\Middleware\Cors::class,
          ];
          

          在 Routes 中,您可以使用带有组的中间件或直接指向特定路由,例如:

          Route::match(['post', 'options'], 'api/...', 'Api\XController@method')->middleware('cors');
          

          如果有人对 jQuery 有这个问题,我建议使用 $.ajax,而不是 $.get、$.post。当你使用这个方法时,jQuery 使用 XMLHttpRequest 发送数据并将 content-type 设置为 application/x-www-form-urlencoded,这是不可能改变的,所以,使用 Ajax。

          例如:

                  $.ajax({
                      type: 'POST',
                      url: 'www.foo.bar/api',
                      contentType: "application/json",
                      xhrFields: {
                          // The 'xhrFields' property sets additional fields on the XMLHttpRequest.
                          // This can be used to set the 'withCredentials' property.
                          // Set the value to 'true' if you'd like to pass cookies to the server.
                          // If this is enabled, your server must respond with the header
                          // 'Access-Control-Allow-Credentials: true'.
                          withCredentials: true
          
                      },
          
                      headers: {
                          // Set any custom headers here.
                          // If you set any non-simple headers, your server must include these
                          // headers in the 'Access-Control-Allow-Headers' response header.
                          'Accept': 'application/json'
                      },
          
          
          
                      data: '{"some":"json data"}',
                      success: function (data) {
                          console.log('AJAX version');
                          console.log("Works!")
                      },
                  });
          

          请记住:如果您在请求标头上使用 application/json,则必须提供“OPTIONS”方法才能进行预检。

          更多关于 CORS 的信息:http://www.html5rocks.com/en/tutorials/cors/

          【讨论】:

          • 还有一件事。如果在您的控制器中返回一个新的响应,Resnpose::json()Response::make() 等,您需要再次设置标头(第三个参数),因为中间件设置的标头不会传递给新的响应实例。
          • 就我而言,当我将 withCredentials: true 更改为 false 时
          【解决方案7】:

          我做了什么,但不确定这是否是最好的解决方案,但没有任何问题

          1.通常使用ng build --prod构建角度

          2.将angular/dist的内容移动到laravel/public

          3.然后在laravel/routes/web.php中使用这个简单的代码

          Route::prefix('api')->group(function () {
              Route::get('/', function () {
              return view('welcome');
              });
          });
          Route::get('/{params?}', function () {
          //    return view('welcome');
              include_once '../public/index.html';
          })->where('params', '(.*)');
          

          现在所有请求都到达 Laravel,如果它可以通过路由捕获请求,则该路由将起作用,否则它将传递给 angular

          【讨论】:

            猜你喜欢
            • 2017-02-13
            • 2017-05-07
            • 2014-12-21
            • 2013-06-02
            • 2014-10-19
            • 2014-06-01
            • 1970-01-01
            • 2015-04-12
            • 2018-05-04
            相关资源
            最近更新 更多