我正在使用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'
});
},
非常感谢
编辑: 这是与我的所有控制器关联的构造函数(所有控制器扩展单个控制器,其中构造方法是:)
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');
}
答案 0 :(得分:3)
您使用的是Access-Control-Allow-Headers吗?
用于响应预检请求以指示哪些HTTP标头 可以在提出实际请求时使用。
尝试将以下标题添加到预检代码中。
header("Access-Control-Allow-Headers: content-type, origin, accept, X-API-KEY");
我记得有类似的问题,似乎也记得其中一些也是浏览器特定的......
如果它有帮助,这里有一些我认识的代码片段:
// 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.
更新:好的,我想我现在更能理解你的问题了。发布了更多代码。首先,是的,我们在那里做的基本相同。我只是检查一下预检试图按标题列出它应该具有的内容。
我认为您缺少的部分是预检应该/不会有您尝试发送的自定义标题。请在此处查看答案:How do you send a custom header in a cross-domain (CORS) XMLHttpRequest?)。就像我一样,您可以检查Access-Control-Request-Headers:
是否与预检一起发送,但是您不应该检查该呼叫上是否存在实际的标头。
听起来你只需要在服务器端移动一些代码 - 让预检非常香草和愚蠢,然后在成功预检后进行实际验证或检查自定义标题。
我使用自带有效负载的HMAC签名来验证预检后的事情。我还检查是否提供了自定义x-app-sig以及我期望的内容,尽管这可能是多余的。
答案 1 :(得分:0)
我已经和这个问题决斗了两天。最终,这个请购单必须有一个变化,并且它很简单。首先,您必须允许发送的头字段(包含所有CORS头),在我的情况下它是:
<?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');
然后,只要请求OPTIONS方法到来,我就必须返回状态“204 No Content”。您可以使用如下条件语句:
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('HTTP/1.1 204 No Content');
}