我正在嘗試使用Microsoft Graph API使用Ajax調用來上傳大文件。使用Ajax調用上傳大文件
根據documentation,你首先必須創建一個上傳會話,我可以成功地使用我的代碼。當我開始上傳到返回的uploadUrl
時,問題就出現了。我得到以下錯誤:
{
code: "invalidRequest",
message: "The Content-Range header length does not match the provided number of bytes."
}
所以,當我檢查提琴手的實際要求,我可以看到Content-Length
頭被設置爲0
。
所以,我想我的Content-Length
頭設置到我發送ArrayBuffer
的大小,但我得到一個錯誤(鉻),上面寫着:
Refused to set unsafe header "Content-Length"
我一直在爲此而努力現在整整兩天,而且我在智慧的結尾。 Microsoft Graph API上的文檔很少,而且看起來與我正在嘗試完成的示例更少。
我無法想象我是唯一一個試圖做到這一點的人,我會認爲這將是一個相當普遍的想法?
以下是我正在使用的代碼。我在其他地方獲得了我的AccessToken
和URL
,但它們似乎沒問題,因爲我可以從控制檯使用它們進行查詢。
this.UploadLargeFileToFolderID = function (FolderID,
FileObject,
ShowLoadingMessage,
SuccessFunction,
ErrorFunction,
CompleteFunction) { //will upload a file up to 60Mb to folder.
//shows the loading messag
ShowLoadingMessage && ThisRepository.LoadingMessage.Show();
//cleans the file name to something acceptable to SharePoint
FileObject.name = CleanOneDriveFileName(FileObject.name);
var UploadSessionURL = FolderID ?
ThisRepository.RepositoryRootURL + '/drive/items/' + FolderID + '/createUploadSession' :
ThisRepository.RepositoryRootURL + '/drive/root/createUploadSession';
//First, get the Upload Sesion.
$.ajax({
url: UploadSessionURL,
method: 'POST',
headers: {
authorization: "Bearer " + ThisRepository.AccessToken
},
success: function (data, textStatus, jqXHR) {
//successfully got the upload session.
console.log('Session:');
console.log(data);
//Create the ArrayBuffer and upload the file.
ReturnArrayBufferFromFile(FileObject, function (ArrayBuffer) {
console.log('Array Buffer:');
console.log(ArrayBuffer);
var MaxChunkSize = 327680;
var ChunkSize = ArrayBuffer.byteLength < MaxChunkSize ?
ArrayBuffer.byteLength :
MaxChunkSize;
chunkedUpload(data.uploadUrl, ArrayBuffer, ChunkSize, 0, null,
null, null, null,
function (response) {
console.log(response);
!SuccessFunction && console.log(response);
typeof SuccessFunction === 'function' && SuccessFunction(response);
});
});
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
typeof ErrorFunction === 'function' && ErrorFunction(jqXHR);
},
complete: function (jqXHR, textStatus) {
ThisRepository.LoadingMessage.Remove();
typeof CompleteFunction === 'function' && CompleteFunction(jqXHR);
},
});
};
函數返回的數組緩衝區發送
function ReturnArrayBufferFromFile(InputFile, CallBackFunction) {
console.log('Input File');
console.log(InputFile);
var FileName = CleanOneDriveFileName(InputFile.name);
var FileUploadReader = new FileReader();
if (InputFile.type.match('image.*')) {
// if the file is an image, we want to make sure
// it's not too big before we return it.
FileUploadReader.onloadend = function (e) {
var img = new Image();
//will resize an image to a maximum of 2 megapixels.
img.onload = function() {
var MAX_HEIGHT = 2048; //max final height, in pixels
var MAX_WIDTH = 2048; //max final width, in pixels
var height = img.height;
var width = img.width;
//do the resizing
if (width > height) { //landscape image
if (width > MAX_WIDTH) {
height *= MAX_WIDTH/width;
width = MAX_WIDTH;
};
} else { //portrait image
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT/height;
height = MAX_HEIGHT;
};
};
//Create a new canvas element, correctly sized with the image
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(this, 0, 0, width, height);
//Create the new file reader for the upload function.
var ConvertedFile = canvas.toBlob(function (blob) {
var ConvertedFileReader = new FileReader();
ConvertedFileReader.onloadend = function (loadendevent) {
//return loadendevent.target.result;
var result = loadendevent.target.result;
var Rawresult = result.split(',')[1];
CallBackFunction(loadendevent.target.result);
};
ConvertedFileReader.readAsArrayBuffer(blob);
}, 'image/jpeg', 0.90);
};
img.src = e.target.result;
};
FileUploadReader.readAsArrayBuffer(InputFile);
} else {
//File is not an image. No pre-work is required. Just upload it.
FileUploadReader.onloadend = function (e) {
CallBackFunction(e.target.result);
};
FileUploadReader.readAsArrayBuffer(InputFile);
};
};
最後,chunkUpload功能:
function chunkedUpload(url, file, chunkSize, chunkStart,
chunkEnd, chunks, chunksDone, fileChunk, CompleteCallBack) {
var filesize = file.byteLength;
chunkSize = chunkSize ? chunkSize : 327680;
chunkStart = chunkStart ? chunkStart : 0;
chunkEnd = chunkEnd ? chunkEnd : chunkSize;
chunks = chunks ? chunks : filesize/chunkSize;
chunksDone = chunksDone ? chunksDone : 0;
fileChunk = fileChunk ? fileChunk : file.slice(chunkStart, chunkEnd);
var req = new XMLHttpRequest();
req.open("PUT", url, true);
//req.setRequestHeader("Content-Length", file.size.toString());
req.setRequestHeader("Content-Range", "bytes " + chunkStart + "-" +
(chunkEnd - 1) + "/" + filesize);
req.onload = (e) => {
let response = JSON.parse(req.response);
console.log(response);
if (response.nextExpectedRanges) {
let range = response.nextExpectedRanges[0].split('-'),
chunkStart = Number(range[0]),
nextChunk = chunkStart + chunkSize,
chunkEnd = nextChunk > file.byteLength ? file.byteLength : nextChunk;
console.log(((chunksDone++/ chunks) * 100), '%');
chunkedUpload(url, file, chunkSize, chunkStart,
chunkEnd, chunks, chunksDone, CompleteCallBack);
}
else {
console.log("upload session complete");
typeof CompleteCallBack === 'function' &&
CompleteCallBack(response);
}
}; req.send(file);
}
貴'PUT'要求有一個'轉移,Encoding'頭?如果是這樣,那麼價值是什麼? – Brad
不,我沒有Transfer-Encoding標頭 - 我從MS Graph API文檔中沒有看到它的必要條件。我應該有嗎? –
不,但我想確保分塊編碼沒有出現在圖片中。瀏覽器應該正確地設置'Content-Length'頭部,所以它是0的事實很有趣。 – Brad