跨域上传

3
有没有办法使用指向url B的“action”属性的表单在url A中上传文件,而不会将页面重定向到url B?

你的问题有点不清楚。你能更明确地解释一下你所说的“重定向”是什么意思吗? - JohnFx
通常情况下,当您提交表单时,它会重定向到“action”中定义的URL。我想知道是否有办法不这样做。我知道可以通过Javascript/Ajax,Iframes等方式实现,但这些解决方案存在一些跨域问题。我只是想听听你们的想法。 - developarvin
那你想要一个不涉及脚本的解决方案?就是纯HTML?那不行。你需要用到AJAX来提交表单而不刷新整个页面。 - JohnFx
我对那些解决方案持开放态度。我的唯一限制是不使用Flash/SWFUpload。 - developarvin
可能是重复的问题:如何通过JavaScript发送跨域POST请求? - JohnFx
1个回答

0

我知道已经过去了3年,但由于今天我自己也有同样的问题,所以我想在这里发布我的解决方案。它不是最漂亮的,但它使用了一个iframe,这应该使它更受到旧版浏览器的支持。 iframe的最大挑战是,出于安全原因(浏览器限制了该功能),如果它位于另一个域上,则无法读取iframe的内容。

本质上,我的解决方案如下:

  1. 用户选择要上传的文件。
  2. 包含文件字段的表单发送针对隐藏iframe的POST请求。
  3. PHP脚本在处理程序脚本中执行,上传文件。
  4. 当脚本完成(或出错)时,它会发送一个Location重定向,将iframe发送回HTTP_REFERER,这将在与表单页面相同的域上,这意味着脚本将能够读取内容。
  5. 为了在重定向中发送有用的信息,我只需添加到引荐页面的GET参数即可。这些可以通过JavaScript提取和读取。

HTML代码:

<form method="post" action="http://other/website/upload.php" enctype="multipart/form-data">
    <input type="file" name="file" />
</form>
<br /><br />
<img id="avatar" />

JavaScript:

$('form').submit(function () {
    $('<iframe></iframe>').attr({name: 'iframe', id: 'iframe'}).prependTo($('body')).load(function () {
        var response = JSON.parse(decodeURIComponent(/[\\?&]_response=([^&#]*)/.exec(this.contentWindow.location.href)[1]).replace(/\+/g, ' '));
        if (response.error) {
            alert(response.error);
        } else {
            $('#avatar').attr('src', response.url);
        }

        $(this).remove();
    });
    $(this).attr('target', 'iframe');
});

$('input[name="avatar"]').change(function () {
    $('form').submit();
});

PHP:

<?php
define('MAX_SIZE', 28 * 1024); // 28 KB
define('UPLOAD_PATH', 'uploads/');
define('UPLOAD_URI', 'http://other/website/uploads/');

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

function format_size ($bytes) {
    for ($labels = array ('B', 'KB', 'MB', 'GB', 'TB'), $x = 0; $bytes >= 1024 && $x < count($labels)-1; $bytes /= 1024, ++$x);
    return round($bytes, 2) . ' ' . $labels[$x];
}

function respond ($message) {
    parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
    $params = array_merge($params, array ('_response' => json_encode($message)));
    header('Location: ' . $_SERVER['HTTP_REFERER'] . '?' . http_build_query($params));
    exit;
}

if (isset($_FILES['file'])) {
    $file = $_FILES['file'];
    switch ($file['error']) {
        case UPLOAD_ERR_INI_SIZE:
        case UPLOAD_ERR_FORM_SIZE:
            respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
            break;
        case UPLOAD_ERR_PARTIAL:
        case UPLOAD_ERR_NO_TMP_DIR:
        case UPLOAD_ERR_CANT_WRITE:
        case UPLOAD_ERR_EXTENSION:
            respond(array ('error' => 'The server could not upload the file.'));
            break;
    }

    if ($file['size'] > MAX_SIZE) {
        respond(array ('error' => 'You may not upload a file larger than ' . format_size(MAX_SIZE) . '.'));
    } else if (!in_array($file['type'], array ('image/png', 'image/gif', 'image/jpeg'))) {
        respond(array ('error' => 'The uploaded file must be a PNG, GIF, or JPEG image.'));
    }

    $split = explode('.', basename($file['name']));
    $ext = array_pop($split);
    $name = implode('.', array_merge($split, array (uniqid(), $ext)));
    if (!move_uploaded_file($file['tmp_name'], UPLOAD_PATH . $name)) {
        respond(array ('error' => 'The server could not upload the file.'));
    } else {
        respond(array ('url' => UPLOAD_URI . $name));
    }
}
?>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接