admin管理员组文章数量:1355758
I'm working with CodeIgniter and the Restfull API to structure my web server private API.
I've started using CORS as per requirements for some framework I'm using.
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).
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.
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) {
mon.handle_errors(error, home.friendsWall);
}, options);
} else {
// in this case, user has disabled geolocatoin !
mon.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'
});
},
Many thanks
EDIT: 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');
}
I'm working with CodeIgniter and the Restfull API to structure my web server private API.
I've started using CORS as per requirements for some framework I'm using.
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).
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.
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) {
mon.handle_errors(error, home.friendsWall);
}, options);
} else {
// in this case, user has disabled geolocatoin !
mon.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'
});
},
Many thanks
EDIT: 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');
}
Share
Improve this question
edited Jun 18, 2015 at 17:42
Miles M.
asked Jun 18, 2015 at 16:03
Miles M.Miles M.
4,16913 gold badges65 silver badges110 bronze badges
2 Answers
Reset to default 3Are you using Access-Control-Allow-Headers?
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.
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.
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.
I have been dueling with this issue for two days. It es out, in the end, there must be a flux for this requisitions and it is quit simple. First you have to allow the header fields that are being sent (with all the CORS headers), in my case it was:
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: authorization, content-type, x-requested-with');
Then I simply had to return status "204 No Content" whenever an request OPTIONS method came. You can use a condition statement like so:
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('HTTP/1.1 204 No Content');
}
本文标签: javascriptHow to handle custom headers with CORS Preflight request AJAXCodeIgniterStack Overflow
版权声明:本文标题:javascript - How to handle custom headers with CORS Pre-flight request? AJAX - CodeIgniter - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744052418a2582663.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论