Laravel 5 + AngularJS交叉域CORS

时间:2022-08-22 19:17:04

I have searched everywhere for an answer but nothing have worked so far. All the listed solutions on stack have not proven to be sufficient.

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

I get nothing in my laravel log in form of errors and I only get the standard:

我的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 controller:

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 Routes:

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',
]);

Kind of bloated not organized angular:

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

//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) {



});

I have no clue where to go from here. I have tried everything from the normal header() implementation to using laravel-cors package to implement via filters and the _construct in the controller. I have also gone the server config route and tried adding the header to the .htaccess and the virtualhost config.

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

7 个解决方案

#1


4  

I had the same problem, but with jQuery and took me weeks to get a good solution.

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

I my case create an middleware to set headers was the perfect solution.

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

Create a Cors middleware: App\Http\Middleware\Cors.php

创建一个Cors中间件:App\Http\中间件\ cortex .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');
    }
}

Remember to set Cors alias inside App\Http\Kernel

记住在App\Http\内核中设置Cors别名。

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

Inside Routes you can use middleware with group or direct to an specific route, in e.g.:

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

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

If someone have this problem with jQuery, I recommend to use $.ajax, instead of $.get, $.post. When you use this methods, jQuery send data using XMLHttpRequest and set content-type to application/x-www-form-urlencoded, it's impossible to change that, so, use Ajax.

如果有人对jQuery有这个问题,我建议使用$。ajax,而不是美元。,$ . post。当您使用此方法时,jQuery将使用XMLHttpRequest发送数据,并将内容类型设置为应用程序/x-www-form-urlencode,因此不可能更改这一点,因此,使用Ajax。

e.g.:

例如:

        $.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!")
            },
        });

Remember: If you are using application/json on request header you must provide "OPTIONS" method, to do a preflight.

请记住:如果您在请求头中使用application/json,您必须提供“选项”方法,以便进行预先飞行。

More info about CORS: http://www.html5rocks.com/en/tutorials/cors/

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

#2


3  

Add this line before return header("Access-Control-Allow-Origin: *");

在返回标题之前添加这一行(“accesscontrol - control - allow- origin: *”);

Your code should be

您的代码应该

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

#3


0  

I don't have good knowledge in laravel.but My suggestion is to the request headers to access REST Methods(GET,POST,PUT,DELTE) and origin to specific domain from which domain your making request in the following way or else set to '*'(it allows any domain)

我对拉腊威尔不太了解。但是我的建议是请求头访问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');

At angular js.If you use <1.2 you can set CORS in controller file like following way.In latest version not required it will set default.you need to set what content type your expecting from server default is json.If your expecting other type of content you can set manually in the request.

在角js。如果使用<1.2,可以在控制器文件中设置CORS,如下所示。在最新版本中,它将设置默认值。您需要设置服务器默认的内容类型是json。如果您希望获得其他类型的内容,可以在请求中手动设置。

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

#4


0  

When you invoke a cross origin XHR request, javascript first fires an OPTIONS request to the given URL. If this method hasnt added in your routes, then it pops a 404 page which is served without the ACAO header so the concrete POST request wont be sent, as javascript see it not allowed to.

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

#5


0  

add

添加

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

to public/index.php if it doesn't work in the function like blue bells suggested

公共/索引。如果php不能像蓝铃建议的那样在函数中工作

#6


0  

Add these lines in your public/index.php:

在您的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 

See, if that works.

看,如果这工作。

#7


0  

what i have done but not sure if that is the best solution but there are no cors with that one

我做了什么,但不确定这是否是最好的解决方案,但是没有cors和那个!

1.build the angular normally using ng build --prod

1。使用ng构建正常的角度——prod

2.move the content of angular/dist to laravel/public

2。将角度/区域的内容移动到laravel/public

3.then use this simple code in laravel/routes/web.php

3所示。然后在laravel/route /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', '(.*)');

now all requests comes to Laravel and if it can catch the request with a route this route will work otherwise it will pass it to angular

现在所有的请求都到了Laravel,如果它能通过一条路径捕获请求,那么这条路径将会工作,否则它将会传递给这个角

#1


4  

I had the same problem, but with jQuery and took me weeks to get a good solution.

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

I my case create an middleware to set headers was the perfect solution.

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

Create a Cors middleware: App\Http\Middleware\Cors.php

创建一个Cors中间件:App\Http\中间件\ cortex .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');
    }
}

Remember to set Cors alias inside App\Http\Kernel

记住在App\Http\内核中设置Cors别名。

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

Inside Routes you can use middleware with group or direct to an specific route, in e.g.:

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

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

If someone have this problem with jQuery, I recommend to use $.ajax, instead of $.get, $.post. When you use this methods, jQuery send data using XMLHttpRequest and set content-type to application/x-www-form-urlencoded, it's impossible to change that, so, use Ajax.

如果有人对jQuery有这个问题,我建议使用$。ajax,而不是美元。,$ . post。当您使用此方法时,jQuery将使用XMLHttpRequest发送数据,并将内容类型设置为应用程序/x-www-form-urlencode,因此不可能更改这一点,因此,使用Ajax。

e.g.:

例如:

        $.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!")
            },
        });

Remember: If you are using application/json on request header you must provide "OPTIONS" method, to do a preflight.

请记住:如果您在请求头中使用application/json,您必须提供“选项”方法,以便进行预先飞行。

More info about CORS: http://www.html5rocks.com/en/tutorials/cors/

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

#2


3  

Add this line before return header("Access-Control-Allow-Origin: *");

在返回标题之前添加这一行(“accesscontrol - control - allow- origin: *”);

Your code should be

您的代码应该

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

#3


0  

I don't have good knowledge in laravel.but My suggestion is to the request headers to access REST Methods(GET,POST,PUT,DELTE) and origin to specific domain from which domain your making request in the following way or else set to '*'(it allows any domain)

我对拉腊威尔不太了解。但是我的建议是请求头访问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');

At angular js.If you use <1.2 you can set CORS in controller file like following way.In latest version not required it will set default.you need to set what content type your expecting from server default is json.If your expecting other type of content you can set manually in the request.

在角js。如果使用<1.2,可以在控制器文件中设置CORS,如下所示。在最新版本中,它将设置默认值。您需要设置服务器默认的内容类型是json。如果您希望获得其他类型的内容,可以在请求中手动设置。

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

#4


0  

When you invoke a cross origin XHR request, javascript first fires an OPTIONS request to the given URL. If this method hasnt added in your routes, then it pops a 404 page which is served without the ACAO header so the concrete POST request wont be sent, as javascript see it not allowed to.

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

#5


0  

add

添加

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

to public/index.php if it doesn't work in the function like blue bells suggested

公共/索引。如果php不能像蓝铃建议的那样在函数中工作

#6


0  

Add these lines in your public/index.php:

在您的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 

See, if that works.

看,如果这工作。

#7


0  

what i have done but not sure if that is the best solution but there are no cors with that one

我做了什么,但不确定这是否是最好的解决方案,但是没有cors和那个!

1.build the angular normally using ng build --prod

1。使用ng构建正常的角度——prod

2.move the content of angular/dist to laravel/public

2。将角度/区域的内容移动到laravel/public

3.then use this simple code in laravel/routes/web.php

3所示。然后在laravel/route /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', '(.*)');

now all requests comes to Laravel and if it can catch the request with a route this route will work otherwise it will pass it to angular

现在所有的请求都到了Laravel,如果它能通过一条路径捕获请求,那么这条路径将会工作,否则它将会传递给这个角