php - ajax 文件上传仅在 SSL 终止负载平衡器时失败

标签 php jquery ajax ssl file-upload

当我们不使用 SSL 时,使用 ajax 上传文件工作正常,但当我们使用时失败。也就是说,在我们的开发服务器(无 SSL)上,以下工作。在我们放入 SSL 之前,它在生产环境中也运行良好。

我们的服务器基础设施(在 rackspace)现在在负载均衡器上有 SSL 终止,这样 session 就可以与其中一个网络服务器 Hook 。我们还使用 .htaccess 来检查 {HTTP:X-Forwarded-Proto} 并强制使用 HTTPS。如果我们删除强制使用 SSL 的 .htaccess 并使用 HTTP 发出以下请求,它就可以工作。将 .htaccess 放回原位,除文件上传部分外,其他一切仍然正常。所有其他 ajax 调用都很好,表单已构建且按钮正常工作......

这是 .htaccess 文件:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI}

js/widget-groups.js 构建一个模态表单来创建或更新组的详细信息,包括组 Logo 的文件上传。它基于 UserFrosting,并且表单不是特别有趣。相关位是:

    /* Display a modal form for updating/creating a group */
function groupForm(box_id, group_id) {
    group_id = typeof group_id !== 'undefined' ? group_id : "";

    // Delete any existing instance of the form with the same name
    if($('#' + box_id).length ) {
        $('#' + box_id).remove();
    }

    var data = {
        box_id: box_id,
        render_mode: 'modal'
    };

    if (group_id != "") {
        console.log("Update mode");
        data['group_id'] = group_id;
        data['show_dates'] = true;
    }

    // Generate the form
    $.ajax({
      type: "GET",
      url: "load_form_group.php",
      data: data,
      dataType: 'json',
      cache: false
    })
    .fail(function(result) {
        addAlert("danger", "Oops, looks like our server might have goofed.  If you're an admin, please check the PHP error logs.");
        alertWidget('display-alerts');
    })
    .done(function(result) {
        // Append the form as a modal dialog to the body
        $( "body" ).append(result['data']);
        $('#' + box_id).modal('show');

        // Link submission buttons
        $('#' + box_id + ' form').submit(function(e){
            var errorMessages = validateFormFields(box_id);
console.log("in widget Link submission buttons");
            var myFileList = document.getElementById('image_url').files;
            myFileList = typeof myFileList !== 'undefined' ? myFileList : false;
console.log(myFileList);
/*
            var myFile = myFileList[0];
console.log(myFile);
console.log("filename="+myFile.name+",size="+myFile.size+",type="+myFile.type);
*/

            if (errorMessages.length > 0) {
                $('#' + box_id + ' .dialog-alert').html("");
                $.each(errorMessages, function (idx, msg) {
                    $('#' + box_id + ' .dialog-alert').append("<div class='alert alert-danger'>" + msg + "</div>");
                });
            } else {
                if (group_id != "") {
                    updateGroup(myFileList,box_id, group_id);
                    } else {
                    createGroup(myFileList,box_id);
                    }
            }

            e.preventDefault();
        });
    });
    }

当用户点击按钮时,将调用 updateGroup:

// Update group with specified data from the dialog
function updateGroup(myFileList,dialog_id, group_id) {
var data = {
    group_id: group_id,
    display_name: $('#' + dialog_id + ' input[name="display_name"]' ).val(),
    group_logo: $('#' + dialog_id + ' input[name="group_logo"]' ).val(),
    csrf_token: $('#' + dialog_id + ' input[name="csrf_token"]' ).val(),
    compAddr1: $('#' + dialog_id + ' input[name="compAddr1"]' ).val(),
    compAddr2: $('#' + dialog_id + ' input[name="compAddr2"]' ).val(),
    compAddr3: $('#' + dialog_id + ' input[name="compAddr3"]' ).val(),
    compCity: $('#' + dialog_id + ' input[name="compCity"]' ).val(),
    compSt: $('#' + dialog_id + ' input[name="compSt"]' ).val(),
    compZip: $('#' + dialog_id + ' input[name="compZip"]' ).val(),
    compCountry: $('#' + dialog_id + ' input[name="compCountry"]' ).val(),
    ajaxMode:   "true"
}

var url = "update_group.php";
$.ajax({
  type: "POST",
  url: url,
  data: data,
}).done(function(result) {
    processJSONResult(result);
    saveImageUrl(myFileList,group_id);
    window.location.reload();
});
return;
}

成功并依次调用 saveImageUrl:

    function saveImageUrl(myFileList,group) {
    if (group==false) return false;
    if (myFileList.length!=1) return false;
        // Create a temporary formdata object and add the files
            myurl="upload.php";
console.log("saveImageUrl. myFileList="+myFileList+". group=" + group + ". myurl=" + myurl);
console.log("myFileList[length]="+myFileList[length]);
console.log("myFileList.length="+myFileList.length);
            var data = new FormData();
            data.append("group",group);
            $.each(myFileList, function(key, value)
                {
                data.append(key, value);
                });
/** alternate
            var xhr = new XMLHttpRequest();
            xhr.open('POST','upload.php',true);
            xhr.onreadystatechange = function() {
                console.log("onreadystatechange state="+xhr.readyState);
                console.log("onreadystatechange status="+xhr.status);
                console.log("onreadystatechange responseText="+xhr.responseText);
                };
            xhr.send(data);
**/
            $.ajax({
                url: myurl,
                type: 'POST',
                data: data,
                cache: false,
                processData: false, // Don't process the files
                contentType: false, // Set content type to false as jQuery will tell the server its a query string request
                success: function(data)
                    {
console.log("upload success with data=");
console.log(data);
                    },
                error: function(data)
                    {
console.log("upload error with data=");
console.log(data);
                    }
                });
console.log("image_url=" + image_url);
}

所有额外的评论都是为了了解发生了什么。

upload.php 文件的开头和结尾是:

<?php
file_put_contents('uploads/debug.txt','---upload+',FILE_APPEND);

...

echo json_encode(array(
    "files" => $files,
    "errors" => count($errors),
    "successes" => count($successes)));

?>

同样,证据表明 file_put_contents 在我们不使用 SSL 时工作正常,但在我们使用时不会被触及。使用 Firebug ,控制台显示对 upload.php 的调用,尽管它总是以红色显示,我们最终出现错误: block ,但“console.log(data)”行没有内容。这可能只是返回 json 的问题,尽管对我来说这看起来没问题。我认为,真正的问题是它在不使用 SSL 时成功,但在我们使用它时失败。成功了,文件通过 update.php 上传并保存在正确的位置。

我不明白 SSL 更改会产生怎样的影响。其他ajax调用没问题;这只是那个有问题的人

processData: false, // Don't process the files
contentType: false, // Set content type to false or jQuery will tell the server its a string

据我所知,这是正确处理 ajax 文件上传所必需的。

是否还有更多我不了解的事情在幕后发生?

谢谢, 埃里克

最佳答案

问题的核心是顺序 ajax 调用。在开发和非 SSL 生产中,它运行良好。但是,对于 SSL,真正的问题浮出水面:时间。

解决方案是添加:

async: false,

对 upload.php 的 ajax 调用。将它添加到第一个 ajax 请求并没有帮助。仅将其添加到第二个。

与许多问题一样,原帖中的表述并不十分准确,但我发现了很多类似的问题,但没有多少令人满意的答案。希望这将是其他人搜索中的又一条线索。

埃里克

关于php - ajax 文件上传仅在 SSL 终止负载平衡器时失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25062202/

相关文章:

jQuery - 替换字符串中某个字符的所有实例

javascript - 尝试使用 Web Speech API 从 Google 图片获取内容时出现 500 服务器错误

javascript - 如何使用 jquery、javascript、ajax 将模态信息发布到 api

jquery - 使用 jquery 按需 javascript 调用窗口卸载

php - cURLlib/File_get_contents 只加载部分数据

javascript - Meteor JS - 加载每个模板后启动功能

php - Yii2 在 sql 中插入日期和时间

javascript - JQuery IF 文档 url = "../products.html"然后执行此操作

php - 我使用什么类型的 PHP 数据类型?

php - 无法通过套接字连接到本地 MySQL 服务器 '/tmp/mysql.sock' (2) 错误