CORS无法在php slim框架中工作

问题描述 投票:3回答:7

我用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');

 ?>
javascript php cors slim
7个回答
4
投票

在您的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


1
投票

对于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"

希望这可以帮助。


1
投票

我最终创建了这个简单的中间件类:

<?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');

0
投票

$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']看起来不对劲。那个有效的_SERVER变量?你的意思是只是REQUEST_METHOD

ORIGIN标头实际上是否真的被发送了?信任错误消息。

你可以使用像WireShark这样的东西,或者至少单步执行你的代码吗?甚至回显/日志调用,以确保您的逻辑按预期工作。


0
投票

我有同样的问题,但最后我实现了它的工作

我正在使用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键。如果你尝试使用"*"它将失败。您必须至少枚举这两个标头。


0
投票

在处理离子混合移动应用程序时,我遇到了同样的问题。我在下面的代码中添加了以下代码到我的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');

-1
投票

按照以下链接中的懒惰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作为域名来源,它也不起作用。

© www.soinside.com 2019 - 2024. All rights reserved.