我用php slim框架创建了rest api。这是我的代码
<?php
require 'Slim/Slim.php';
require '../lib/cors_enable.php';
require '../lib/logger.php';
require '../../db_config/config.php';
require '../lib/predis-0.8/lib/Predis/Autoloader.php';
Predis\Autoloader::register();
require '../lib/RedisMethods.php';
require '../lib/APICaller.php';
require '../lib/FosterGemOAuth.php';
require '../lib/FosterGemUser.php';
require '../lib/NewsFeed.php';
require '../lib/FosterGemBookmarks.php';
require '../lib/TopicWebsite.php';
require '../lib/FetchFullArticle.php';
require '../lib/PushNotification.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
// return only the headers and not the content
// only allow CORS if we're doing a GET - i.e. no saving for now.
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
if($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET' || $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'POST') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With, X-authentication,Content-Type, X-client');
}
}
exit;
}
$app->post('/messagebhej(/)(:profile_id/?)(:app_auth_token/?)', 'messagebhej');
$app->post('/login','login');
$app->run();
function messagebhej($profile_id, $app_auth_token){
$error='';
$request = file_get_contents('php://input');
try {
$request_data = json_decode($request,true);
if($app_auth_token == APP_AUTH_TOKEN){
$obj = new PushNotification();
$res = $obj->sendMessage($profile_id, $request_data);
} else {
$error='Access Denied';
}
} catch (Exception $ex) {
$error=$ex->getMessage();
log_error($error,"index.php | sendMessage function");
}
if($error) {
$return_data= '{"Status":"Failed","Message":"'.$error.'"}';
} else {
$return_data='{"Status":"Success"}';
}
echo $return_data;
}
function login() {
$error='';
$request = file_get_contents('php://input');
try {
$request_data = json_decode($request,true);
if(isset($request_data['EmailAddress']) && isset($request_data['Password'])){
if($request_data['EmailAddress']){
$obj = new FosterGemUser();
$user_data = $obj->get_user($request_data['EmailAddress'],$request_data['Password'],$request);
} else {
$error='Please enter your email address.';
}
} else {
$error='Wrong Data Format.';
}
} catch (Exception $ex) {
$error=$ex->getMessage();
log_error($error,"index.php | login function");
}
if($error) {
$return_data= '{"Status":"Error","Message":"'.$error.'"}';
} else {
$return_data=$user_data;
}
echo $return_data;
}
现在,当我使用Rest客户端调用它时,api工作正常。但是当我从javascript调用login api时它运行良好但是messagebhej api给出了错误
XMLHttpRequest cannot load http://api.fostergem.com/messagebhej/556714b04ec0a40d3cda0118/{app_auth_token}. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63343' is therefore not allowed access. The response had HTTP status code 404.
我疯了一切都是相同的,然后如何为一个api启用cors而不为其他api启用。
这是我的cors_enable.php
<?php
// Specify domains from which requests are allowed
header('Access-Control-Allow-Origin: *');
// Specify which request methods are allowed
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
// Additional headers which may be sent along with the CORS request
// The X-Requested-With header allows jQuery requests to go through
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
// Set the age to 1 day to improve speed/caching.
header('Access-Control-Max-Age: 86400');
?>
在您的API中使用您拥有的条件来包装头文件是没有意义的。
现在只有当REQUEST_METHOD是OPTIONS并且HTTP_ACCESS_CONTROL_REQUEST_METHOD是GET或POST时,它才会设置头,但是你的请求不符合这个要求。
所以更换
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
// return only the headers and not the content
// only allow CORS if we're doing a GET - i.e. no saving for now.
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
if($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET' || $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'POST') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With, X-authentication,Content-Type, X-client');
}
}
exit;
}
来自你的代码
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
PS:除非您将服务器变量设置为HTTP_ACCESS_CONTROL_REQUEST_METHOD,否则将其更改为REQUEST_METHOD
对于Slim Framework 2.4版本,我做了一个小小的黑客来解决Preflight OPTIONS请求
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
if($app->request->isOptions()) {
return true;
break;
}
$app->post('/authenticate', 'authenticateUser');
$app->run();
所以这将跟踪所有OPTIONS请求并返回true,它对我有用。
我的.htaccess文件如下所示
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "X-Requested-With, Content-Type, Accept, Origin, Authorization"
Header add Access-Control-Allow-Methods "GET, POST, OPTIONS"
希望这可以帮助。
我最终创建了这个简单的中间件类:
<?php
class CorsMiddleware
{
private $router;
public function __construct(\Slim\Router $router)
{
$this->router = $router;
}
/**
* Cors middleware invokable class
*
* @param \Psr\Http\Message\ServerRequestInterface $request PSR7 request
* @param \Psr\Http\Message\ResponseInterface $response PSR7 response
* @param callable $next Next middleware
*
* @return \Psr\Http\Message\ResponseInterface
*/
public function __invoke($request, $response, $next)
{
// https://www.html5rocks.com/static/images/cors_server_flowchart.png
if ($request->isOptions()
&& $request->hasHeader('Origin')
&& $request->hasHeader('Access-Control-Request-Method')) {
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', '*')
->withHeader("Access-Control-Allow-Methods", '*');
} else {
$response = $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Expose-Headers', '*');
return $next($request, $response);
}
}
}
我像这样使用它(由于依赖注入,它是一个字符串):
$app->add('CorsMiddleware');
$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']
看起来不对劲。那个有效的_SERVER变量?你的意思是只是REQUEST_METHOD
?
ORIGIN标头实际上是否真的被发送了?信任错误消息。
你可以使用像WireShark这样的东西,或者至少单步执行你的代码吗?甚至回显/日志调用,以确保您的逻辑按预期工作。
我有同样的问题,但最后我实现了它的工作
我正在使用cors-middleware https://github.com/tuupola/cors-middleware
这些是我的设置:
$app->add(new \Tuupola\Middleware\Cors([
"origin" => ["*"],
"methods" => ["GET", "POST", "PUT", "PATCH", "DELETE"],
"headers.allow" => ["Accept", "Content-Type"],
"headers.expose" => [],
"credentials" => false,
"cache" => 0,
"logger" => $container['logger']
]));
注意headers.allow
键。如果你尝试使用"*"
它将失败。您必须至少枚举这两个标头。
在处理离子混合移动应用程序时,我遇到了同样的问题。我在下面的代码中添加了以下代码到我的index.php文件中。
header('Access-Control-Allow-Origin:*');
header('Access-Control-Allow-Headers:X-Request-With');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
按照以下链接中的懒惰CORS的说明...这对我有用...
确切地说,我创建了一个cors.php文件来分隔您处理核心的根并粘贴文件中的所有代码。
http://www.slimframework.com/docs/v3/cookbook/enable-cors.html
UPDATE
因为我从我的内部服务器遇到了这个问题,我有两个Web服务器运行我的后端API而另一个在Angular CLI上,解决方案就在这个环境中。
CORS通过使用OPTIONS方法发送预检请求来检查请求URL是否有效,问题是您的restful API路由器未配置为处理该请求,因此它提供了NOT_FOUND响应。因此,您所做的是将所有OPTIONS请求的路由添加为一个简单的解决方案,尽管您可以更具体。
为了好看又潮湿,创建一个cors.php文件,您将为您的cors路线放置路线并在其中添加此代码
<?php
// Handling CORS with a simple lazy CORS
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://localhost:4200')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
});
// Catch-all route to serve a 404 Not Found page if none of the routes match
// NOTE: make sure this route is defined last
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function($req, $res) {
// handle using the default Slim
$handler = $this->notFoundHandler;
//page not found handler
return $handler($req, $res);
});
基本上这就是说,对于所有路由上的所有选项请求,只需返回响应而不处理它。这里重要的是返回响应后执行的中间件,它设置响应头,告诉浏览器发送真实请求是可以的。
注意:确保cors.php文件属于最后一组路由。也不要将asterix作为域名来源,它也不起作用。