XMLHttpRequest 无法加载 http://www.images.mysite.com/upload.php。请求的资源上不存在 'Access-Control-Allow-Origin' header

XMLHttpRequest cannot load http://www.images.mysite.com/upload.php. No 'Access-Control-Allow-Origin' header is present on the requested resource

我正在从我的网站 www.mysite.com.www.mysite.com.

上的应用程序 运行ning 上传文件到我的子域 images.mysite.url

为此,我使用 dropzone 进行 AJAX 文件上传和 PHP。 选择文件后,它在上传页面和控制台

显示消息 Server responded with 0 code.

XMLHttpRequest cannot load http://www.images.mysite.com/upload.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8085' is therefore not allowed access.

(出于测试目的,我先在本地主机上 运行 上传到服务器后的相同消息)

在服务器上,我的upload.php:

<?php
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
header('Access-Control-Allow-Methods: GET, POST, PUT');
header('content-type: application/json; charset=utf-8');


$uploaddir = '/post/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);

echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
    echo "File is valid, and was successfully uploaded.\n";
} else {
    echo "Possible file upload attack!\n";
}

echo 'Here is some more debugging info:';
print_r($_FILES);

print "</pre>";

?>

空投区

$("i#dzopen").dropzone({
        paramName: "file",
        maxFilesize: 10,
        url: 'http://www.images.mysite.com/upload.php',
        previewsContainer: "#media-upload-previews",
        uploadMultiple: true,
        parallelUploads: 1,
        dataType: 'jsonp',
        maxFiles: 10,
        acceptedFiles: "image/*,audio/*,video/*",
        init: function () {
            this.on("success", function (file, responseText) {
                log("log " + responseText);
                       });                   
                }
            });

如何解决问题?

按原样使用您的代码,Access-Control-Allow-Origin header 应该已经发送。

您可能遇到服务器错误,或其他原因导致无法发送 header(header 已发送?内容已刷新?错误 URL?)。

查看您的控制台和浏览器的开发人员工具网络选项卡是否存在错误,并查看 headers。

在修复阻止发送 header 表单的任何问题后,请考虑以下事项:

  1. Dropzone 发送一个

    Access-Control-Request-Headers:accept, cache-control, content-type, x-requested-with

    header。您没有回复 cache-control 已接受,因此您需要添加它:

    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Cache-Control");
    
  2. 您允许 uploadMultiple,但只需要一个文件。

  3. 您在 dropzone 配置中指定的 paramName 与您在服务器上使用的不同("file"'userfile')。
  4. 您的服务器没有 return 有效 JSON,这是 dropzone 处理程序所期望的。

一个可以帮助您入门的人为示例(不要在生产中使用!):

<?php
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Cache-Control");
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT');
header('content-type: application/json; charset=utf-8');

$uploaddir = '/post/';
$idx = "file";

$res = array("success" => true, "status" =>array());

if (isset($_FILES[$idx]) && is_array($_FILES[$idx])) {
    foreach ($_FILES[$idx]["error"] as $key => $error) {
        $status = array("success" => true);
        if ($error == UPLOAD_ERR_OK) {
            $tmp_name = $_FILES[$idx]["tmp_name"][$key];
            $name = $_FILES[$idx]["name"][$key];
            if (move_uploaded_file($tmp_name, $uploaddir.$name)) {
                $status["message"] = "ok";
            } else {
                $res["success"] = false;
                $status["success"] = false;
                $status["error"] = error_get_last();
                $status["message"] = "internal server error";
            }
        } else {
            $res["success"] = false;
            $status["success"] = false;
            $status["error"] = $error;
            $status["message"] = "upload error";
        }
        $res["status"][] = $status;
    }
}

echo(json_encode($res));

编辑:

原来是服务器问题。 Apache 的 _mod_security_ 阻止了文件上传,但不是正常的 POST 或 GET 请求,并且 returned 406 Not Acceptable.

发行

$ curl http://example.com/upload.php -X POST \
  -F "file[]=@/path/to/file" \
  -v

结果

> POST /upload.php HTTP/1.1
> User-Agent: curl/7.35.0
> Host: images.sitename.com
> Accept: */*
> Content-Length: 719
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------755cbe89e26cbeb1
> 
< HTTP/1.1 100 Continue
< HTTP/1.1 406 Not Acceptable
* Server nginx admin is not blacklisted
< Server: nginx admin
< Date: Mon, 19 Oct 2015 08:06:59 GMT
< Content-Type: text/html; charset=iso-8859-1
< Connection: keep-alive
< Content-Length: 380
* HTTP error before end of send, stop sending
< 

(nginx 充当 reverse-proxy,Apache 在其后面)。 在这种情况下,如果您自己管理服务器,您可以使用 .htaccess 或其他方式禁用有问题的规则:

方法 1 - 完全禁用 mode_security 文件(不太推荐)

<IfModule mod_security2.c>
  SecRuleEngine Off 
</IfModule>

方法 2 - 禁用特定规则

$ cat /var/log/apache2/error.log | grep ModSecurity

(修改路径以指向您的 Apache 错误日志),它应该 returns 像这样的行:

[<date>] [error] [client <...>] ModSecurity: Access denied with code 406 (phase 2). <...> at REQUEST_FILENAME. [file <...>] [id "950004"] [msg <...>] <...>

注意 [id "950004"]

可以通过以下方式禁用它:

<IfModule mod_security2.c>
    SecRuleRemoveById 950004 
</IfModule>

还有其他可能更好的方法。

这里是a good reference for mod_security configuration.