我有一个简单的PHP脚本,我正在尝试跨域CORS请求:

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...

然而,我仍然得到了错误:

Access-Control-Allow-Headers不允许请求报头字段X-Requested-With

我还缺什么吗?


Access-Control-Allow-Headers不允许*作为可接受的值,请参阅Mozilla文档。

您应该发送已接受的报头,而不是星号(如错误所示,第一个X-Requested-With)。

更新:

*现在接受的是Access-Control-Allow-Headers。

根据MDN Web Docs 2021:

值*仅作为没有凭据的请求(没有HTTP cookie或HTTP身份验证信息的请求)的特殊通配符值。在带有凭据的请求中,它被视为没有特殊语义的字面头名称*。注意,Authorization标头不能是通配符,总是需要显式地列出。


正确处理CORS请求稍微复杂一些。下面是一个响应更充分(正确)的函数。

/**
 *  An example CORS-compliant method.  It will allow any GET, POST, or OPTIONS requests from any
 *  origin.
 *
 *  In a production environment, you probably want to be more restrictive, but this gives you
 *  the general idea of what is involved.  For the nitty-gritty low-down, read:
 *
 *  - https://developer.mozilla.org/en/HTTP_access_control
 *  - https://fetch.spec.whatwg.org/#http-cors-protocol
 *
 */
function cors() {
    
    // Allow from any origin
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
        // you want to allow, and if so:
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');    // cache for 1 day
    }
    
    // Access-Control headers are received during OPTIONS requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
            // may also be using PUT, PATCH, HEAD etc
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        
        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
    
        exit(0);
    }
    
    echo "You have CORS!";
}

安全记录

检查HTTP_ORIGIN头文件是否符合已批准的源列表。

如果来源没有被批准,那么您应该拒绝请求。

请阅读说明书。

博士TL;

当浏览器想要执行跨站点请求时,它首先确认对URL的“预飞行”请求是可以的。通过允许CORS,您可以告诉浏览器,来自此URL的响应可以与其他域共享。

CORS不保护您的服务器。CORS试图通过告诉浏览器与其他域共享响应的限制来保护您的用户。通常情况下,这种共享是完全禁止的,因此CORS是在浏览器的正常安全策略中戳一个漏洞的一种方式。这些漏洞应该尽可能小,所以总是检查HTTP_ORIGIN针对某种内部列表。

这里有一些危险,特别是如果URL提供的数据通常是受保护的。您实际上是在允许起源于其他服务器的浏览器内容读取(并可能操作)您服务器上的数据。

如果你打算使用CORS,请仔细阅读协议(它相当小),并试着理解你在做什么。代码示例中给出了一个参考URL。

头的安全

已经观察到HTTP_ORIGIN头是不安全的,这是真的。事实上,对于不同含义的术语来说,所有HTTP报头都是不安全的。除非头文件包含一个可验证的签名/hmac,或者整个对话都是通过TLS验证的,否则头文件只是“浏览器告诉我的东西”。

在这种情况下,浏览器表示“来自域X的对象希望从该URL获得响应。这样可以吗?”CORS的关键是能够回答,“是的,我允许那样做”。


我得到了同样的错误,并在我的后端脚本用下面的PHP修复了它:

header('Access-Control-Allow-Origin: *');

header('Access-Control-Allow-Methods: GET, POST');

header("Access-Control-Allow-Headers: X-Requested-With");

我只是设法让dropzone和其他插件与此修复工作(angularjs + php后端)

 header('Access-Control-Allow-Origin: *'); 
    header("Access-Control-Allow-Credentials: true");
    header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
    header('Access-Control-Max-Age: 1000');
    header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

将此添加到您的upload.php或发送请求的地方(例如,如果您有upload.html,您需要将文件附加到upload.php,然后复制并粘贴这4行)。 此外,如果你在chrome/mozilla中使用CORS插件/插件,请确保切换它们不止一次,以便启用CORS


如果你想从PHP创建一个CORS服务,你可以使用这段代码作为文件中处理请求的第一步:

// Allow from any origin
if(isset($_SERVER["HTTP_ORIGIN"]))
{
    // You can decide if the origin in $_SERVER['HTTP_ORIGIN'] is something you want to allow, or as we do here, just allow all
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
else
{
    //No HTTP_ORIGIN set, so we allow any. You can disallow if needed here
    header("Access-Control-Allow-Origin: *");
}

header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 600");    // cache for 10 minutes

if($_SERVER["REQUEST_METHOD"] == "OPTIONS")
{
    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_METHOD"]))
        header("Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT"); //Make sure you remove those you do not want to support

    if (isset($_SERVER["HTTP_ACCESS_CONTROL_REQUEST_HEADERS"]))
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

    //Just exit with 200 OK with the above headers for OPTIONS method
    exit(0);
}
//From here, handle the request as it is ok

如果我们不能正确理解CORS的功能,它会成为一个令人头痛的问题。我在PHP中使用它们,它们工作起来没有问题。参考这里

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");

许多互联网范围内的描述没有提到指定Access-Control-Allow-Origin是不够的。下面是一个适合我的完整例子:

<?php
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
        header('Access-Control-Allow-Headers: token, Content-Type');
        header('Access-Control-Max-Age: 1728000');
        header('Content-Length: 0');
        header('Content-Type: text/plain');
        die();
    }

    header('Access-Control-Allow-Origin: *');
    header('Content-Type: application/json');

    $ret = [
        'result' => 'OK',
    ];
    print json_encode($ret);

当我使用angular 4作为客户端,使用PHP作为服务器端时,这些代码就可以完成了。

header("Access-Control-Allow-Origin: *");

这应该可以

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");

在.htaccess中添加此代码

在头部添加自定义认证密钥,如app_key,auth_key..等

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers: "customKey1,customKey2, headers, Origin, X-Requested-With, Content-Type, Accept, Authorization"

我使用这5个头,之后解决了cors错误(后端:PHP,前端:VUE JS)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS, post, get');
header("Access-Control-Max-Age", "3600");
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
header("Access-Control-Allow-Credentials", "true");