使用XMLHttpRequest和FileReader设置自定义内容类型和边界来上传二进制文件

时间:2017-05-26 10:53:44

标签: javascript ajax xmlhttprequest filereader

我正在尝试使用XMLHttpRequest和FileReader将(DICOM)二进制文件上传到服务器。

根据DICOM标准,Content-Type muss是multipart/related;type=application/dicom定义的,并且在Request Payload中必须再次为Content-Type:application/dicom,我已设法使用此代码以某种方式构建该结构:

    let boundary = Math.random().toString().substr(2);
    let reader = new FileReader();
    reader.readAsBinaryString(fileList[0]);

    reader.onload = function(e) {

        var xmlHttpRequest = new XMLHttpRequest();
        xmlHttpRequest.open("POST", "myurl", true);
        var dashes = '--';
        var crlf = "\r\n";
        if ( fileList[0].type == '' ){
            filetype = 'application/dicom';
        } else {
            filetype = fileList[0].type;
        }
        let content = e.target["result"];
        var data = dashes + boundary + crlf + "Content-Type: " + filetype + crlf + crlf + content + crlf + dashes + boundary + dashes;
        xmlHttpRequest.setRequestHeader("Content-Type", "multipart/related;type=application/dicom;boundary=" + boundary+";");
        xmlHttpRequest.setRequestHeader("Accept", "application/dicom+json");
        xmlHttpRequest.send(data);
    }; xmlHttpRequest.send(data);
        };

这种方法的问题在于,似乎XMLHttpRequest进行了UTF-8编码并且破坏了二进制数据(参见this post)。

  • 问题是如何使用reader.readAsArrayBuffer()并设置正文内容类型和边界?或
  • 如何阻止XMLHttpRequest进行UTF-8编码?

我的第二个问题是如何使用这种方法处理大文件(大约1 TB)?

1 个答案:

答案 0 :(得分:2)

由于post,我找到了对我(第一部分)问题的答案,现在是我的代码:

var boundary = Math.random().toString().substr(2);
var reader = new FileReader();
reader.readAsArrayBuffer(fileList[0]);
reader.onload = function(e) {
    var xmlHttpRequest = new XMLHttpRequest();
    xmlHttpRequest.open("POST", "myurl", true);
    var dashes = '--';
    var crlf = "\r\n";
    if ( fileList[0].type == '' ){
        filetype = 'application/dicom';
    } else {
        filetype = fileList[0].type;
    }
    var content = e.target["result"];
    var dataView = new DataView(e.target["result"]);
    var postDataStart = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + encodeURIComponent(fileList[0].name) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf;
    var postDataEnd = crlf + dashes + boundary + dashes;
    var size = postDataStart.length + dataView.byteLength + postDataEnd.length;
    var uint8Array = new Uint8Array(size);
    var i = 0;

    for (; i < postDataStart.length; i++) {
          uint8Array[i] = postDataStart.charCodeAt(i) & 0xFF;
    }
    for (let j = 0; j < dataView.byteLength; i++, j++) {
          uint8Array[i] = dataView.getUint8(j);
    }
    for (let j = 0; j < postDataEnd.length; i++, j++) {
         uint8Array[i] = postDataEnd.charCodeAt(j) & 0xFF;
    }
    var payload = uint8Array.buffer;
    xmlHttpRequest.setRequestHeader("Content-Type", "multipart/related;type=application/dicom;boundary=" + boundary+";");
    xmlHttpRequest.setRequestHeader("Accept", "application/dicom+json");
    xmlHttpRequest.send(payload);
};

修改

我找到了另一种解决方案,它使用较大的文件作为可用的RAM,并且流式传输文件而不是首先加载到RAM中:

    var boundary = Math.random().toString().substr(2);
    var xmlHttpRequest = new XMLHttpRequest();
    xmlHttpRequest.open("POST", "myurl", true);
    var dashes = '--';
    var crlf = "\r\n";
    filetype = fileList[0].type;

    var postDataStart = dashes + boundary + crlf + "Content-Disposition: form-data;" + "name=\"file\";" + "filename=\"" + encodeURIComponent(fileList[0].name) + "\"" + crlf + "Content-Type: " + filetype + crlf + crlf;
    var postDataEnd = crlf + dashes + boundary + dashes;

    xmlHttpRequest.setRequestHeader("Content-Type", "multipart/related;type=application/dicom;boundary=" + boundary+";");
    xmlHttpRequest.setRequestHeader("Accept", "application/dicom+json");
    xmlHttpRequest.send(new Blob([new Blob([postDataStart]),fileList[0], new Blob([postDataEnd])]));