Mil*_* M. 6 javascript php ajax jquery codeigniter
我正在使用CodeIgniter和Restfull API来构建我的Web服务器私有API.
我已经开始根据我正在使用的一些框架的要求使用CORS.
使用Jquery,我可以看到2个请求被发送,第一个作为OPTION类型 - 正如预期的那样 - 但是没有我的自定义头(X-API-KEY用于安全性,默认情况下在CodeIgniter Restful API中).
然后,我收到无效的API密钥错误消息,如图所示.然后在正确的标头发送正确的请求之后,同时,第一个请求触发.fail()函数来处理错误.

处理该场景的最佳做法是什么?我希望我的ajax请求能够顺利处理第一个预检OPTION请求,而不会像我今天那样在我的应用程序上触发错误,然后根据CORS的工作方式使用自定义标头进行正常的GET调用并执行成功调用,而不会触发错误在第一次预检请求中打电话?
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'
});
},
Run Code Online (Sandbox Code Playgroud)
非常感谢
编辑:这是与我的所有控制器关联的构造函数(所有控制器扩展单个控制器,其中构造方法是:)
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');
}
Run Code Online (Sandbox Code Playgroud)
您是否使用Access-Control-Allow-Headers?
用于响应预检请求,以指示在发出实际请求时可以使用哪些 HTTP 标头。
尝试将以下标头添加到您的预检代码中。
header("Access-Control-Allow-Headers: content-type, origin, accept, X-API-KEY");
Run Code Online (Sandbox Code Playgroud)
我记得有类似的问题,似乎还记得其中一些是特定于浏览器的......
如果有帮助的话,这是我知道有效的一些代码的片段:
// 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.
Run Code Online (Sandbox Code Playgroud)
更新:好的,我想我现在更好地理解你的问题了。发布了更多代码。首先,是的,我们正在做基本上相同的事情。我只是检查预检是否尝试将其在标头方面应具有的内容列入白名单。
我认为您缺少的部分是预检应该/不会有您尝试发送的自定义标头。请参阅此处的答案:如何在跨域 (CORS) XMLHttpRequest 中发送自定义标头?)。因此,就像我一样,您可以检查它们是否Access-Control-Request-Headers:与预检一起发送,但您不应该检查该调用中是否存在实际标头。
听起来你只需要在服务器端移动一些代码 - 使预检变得非常普通和愚蠢,然后在成功预检后进行实际的身份验证或检查自定义标头。
我自己使用与有效负载一起发送的 HMAC 签名来在预检后进行身份验证。我还检查是否提供了自定义 x-app-sig 以及我所期望的内容,尽管这可能是多余的。