如何使用CORS Pre-flight请求处理自定义标头? AJAX - CodeIgniter [英] How to handle custom headers with CORS Pre-flight request? AJAX - CodeIgniter

查看:161
本文介绍了如何使用CORS Pre-flight请求处理自定义标头? AJAX - CodeIgniter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用CodeIgniter和Restfull API来构建我的Web服务器私有API。

I'm working with CodeIgniter and the Restfull API to structure my web server private API.

我已根据某些框架的要求开始使用CORS了使用。

I've started using CORS as per requirements for some framework I'm using.

使用Jquery,我可以看到2个请求被发送,第一个作为OPTION类型 - 正如预期的那样 - 但是没有我的自定义头(X-API-KEY)为安全起见,默认情况下在CodeIgniter Restful API中。)

Working with Jquery, I can see 2 requests are sent, first one as OPTION type - as expected - but without my custom header (X-API-KEY for security, by default in CodeIgniter Restful API).

然后我收到一条无效的API密钥错误消息,如图所示。然后在正确的标头发送正确的请求之后,同时,第一个请求触发了.fail()函数来处理错误。

I then receive an invalid API Key error message as shown in the picture. Then right after the proper request is being sent with correct headers but in the meantime, the first requests triggered the .fail() function to handle errors.


什么是最佳做法处理那种情况?我希望我的ajax请求能够顺利处理第一个预检OPTION请求,而不会像我今天那样在我的应用程序上触发错误,然后根据CORS的工作方式使用自定义标头进行正常的GET调用并执行成功调用,而不会触发错误在第一个预检请求中调用?

What's best practice to handle that scenario ? i would like my ajax request to smoothly handle the first preflight OPTION request without triggering an error on my app as it does today, then do the normal GET call with custom headers as per how CORS works and execute the success call without never triggering the error call in the first preflight request ?

triggerFriendsWall: function() {
        //Get location
            var options = {
                timeout: 30000,
                enableHighAccuracy: true,
                maximumAge: 90000
            };

            //We need to check if user has disabled geolocation, in which case it makes the app crashes ! (from Cordova.js 1097)
            var position = JSON.parse(localStorage.getItem("position"));

            if (position == "" || position == null || position == "null" || typeof position == "undefined" ) {
                // In this case we have never set location to anything and the user has enabled it.
                navigator.geolocation.getCurrentPosition( function(position) {
                    home.friendsWall(position);
                }, function(error) {
                    common.handle_errors(error, home.friendsWall);
                }, options);
            } else {
                // in this case, user has disabled geolocatoin !
                common.handle_errors(false, home.friendsWall);
            }
},


friendsWall: function(position) {

    $.when(UserDAO.getUsersNearby(position.coords.latitude, position.coords.longitude, home.Usr_radius, home.Usr_limit, home.Usr_offset))
                .done(function(response) {
                   // Do stuff
    })
}


getUsersNearby: function(lat, lng, radius, limit, offset) {
            var key = localStorage.getItem("key");

            return $.ajax({
                type: "GET",
                url: config.server_url + 'user/usersSurrounding',
                headers: {
                    'X-API-KEY': key
                },
                data: {
                    lat: lat,
                    lng: lng,
                    radius: radius,
                    limit: limit,
                    offset: offset
                },
                dataType: 'json'
            });
        },

非常感谢

编辑:
这是与我的所有控制器关联的构造函数(所有控制器扩展单个控制器,其中构造方法是:)

This is the constructor associated to all my controllers ( all controller extend a single controller where construct method is : )

public function __construct()
{

    header('Access-Control-Allow-Origin: *');
    header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method");
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
    $method = $_SERVER['REQUEST_METHOD'];
    if($method == "OPTIONS") {
        die();
    }

    parent::__construct();
    // $this->load->model('admin_model');
    $this->load->library('session');
    $this->load->library('key');
}


推荐答案

你在用 Access-Control-Allow-Headers


用于响应预检请求,以指示在发出实际请求时可以使用哪些HTTP头

Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

尝试将以下标题添加到预检代码中。

Try adding the following header to your preflight code.

header("Access-Control-Allow-Headers: content-type, origin, accept, X-API-KEY");

我记得有类似的问题,似乎还记得其中一些也是浏览器特定的......

I recall having similar issues, seem to recall some of it being browser specific too...

如果有帮助,这里有一些我认识的代码片段:

If it helps here is a snippet from some code I know works:

// CORS and other headers.  Make sure file is not cached (as it happens for example on iOS devices)
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Max-Age: ' . CORS_AUTH_MAX_AGE);

//CORS preflight
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

    header("Access-Control-Allow-Headers: content-type, origin, accept, x-app-sig");

    $acrh = explode(',', strtolower($headers['Access-Control-Request-Headers']));
    foreach ($acrh as $k => $v) {
        $acrh[$k] = trim($v);
    }

    if (! isset($headers['Access-Control-Request-Headers']) || ! in_array('x-app-sig', $acrh)) {
        _log($h, '*** Bad preflight!' . PHP_EOL . print_r($headers, true) . PHP_EOL . print_r($_REQUEST, true));
        header("HTTP/1.1 401 Unauthorized");
        exit; //->
    }

    _log($h, '+++ Successful preflight.' . PHP_EOL . print_r($headers, true) . PHP_EOL . print_r($_REQUEST, true));
    exit; //->
}

//Now we are past preflight.  Actual Auth happens here, I check a signature that I post with payload.

更新好的,我想我现在更了解你的问题。发布了更多代码。首先,是的,我们在那里做的基本相同。我只是检查预检是否试图按标题列出它应该具有的内容。

Update: OK, think I better understand your question now. Posted a bit more code. First off, yes, we are doing essentially the same thing there. I just check that the preflight tried to white-list what it should have in terms of headers.

我认为您缺少的部分是预检应该/不会拥有您要发送的自定义标头。请参阅此处的答案:如何您是否在跨域(CORS)XMLHttpRequest中发送自定义标头?)。就像我一样,您可以检查 Access-Control-Request-Headers:是否与预检一起发送,但是您不应该检查该呼叫上是否存在实际的标头。

I think the part you are missing is that the preflight should/will not have the custom header you are trying to send. See the answer here: How do you send a custom header in a cross-domain (CORS) XMLHttpRequest?). So like I do you could check that the Access-Control-Request-Headers: are sent with the preflight, but you should not check for the actual header being present on that call.

听起来你只需要在服务器端移动一些代码 - 让预检相当香草和愚蠢,然后进行实际验证或检查自定义标题成功预检后。

Sounds like you just need to move a little of the code around server side - make the preflight pretty vanilla and dumb, then do your actual auth or checking of custom headers after successful preflight.

我使用自带有效负载的HMAC签名来验证预检后的事情。我还检查是否提供了自定义x-app-sig,虽然这可能是多余的。

I use a HMAC signature sent with the payload myself to authenticate things after the preflight. I also check that the custom x-app-sig is supplied and what i expect though that is probably redundant.

这篇关于如何使用CORS Pre-flight请求处理自定义标头? AJAX - CodeIgniter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆