OneDrive API Node.js - невозможно использовать:/createUploadSession Ошибка диапазона содержимого
Моя проблема заключалась в том, что я не мог загрузить файлы размером более 4 МБ, поэтому я использовал createuploadsession в соответствии с createuploadsession
Я успешно получил значение uploadUrl из ответа createuploadsession. Теперь я пытаюсь сделать запрос PUT с этим кодом
var file = 'C:\\files\\box.zip'
fs.readFile(file, function read(e, f) {
request.put({
url: 'https://api.onedrive.com/rup/545d583xxxxxxxxxxxxxxxxxxxxxxxxx',
headers: {
'Content-Type': mime.lookup(file),
'Content-Length': f.length,
'Content-Range': 'bytes ' + f.length
}
}, function(er, re, bo) {
console.log('#324324', bo);
});
});
Но я получу в качестве ответа "Недопустимое значение заголовка Content-Range" также, если я попытаюсь
'Content-Range': 'bytes 0-' + f.length
//or
'Content-Range': 'bytes 0-' + f.length + '/' + f.length
Я получу такой же ответ.
Также я не хочу разделять свой файл на части. Я просто хочу загрузить свой файл полностью в 1run. У кого-нибудь есть пример кода для загрузки файла в uploadUrl из ответа createuploadsession. Кроме того, мне действительно нужно сначала загрузить этот загружаемый файл, прежде чем я смогу загружать файлы размером более 4 МБ или есть альтернативный способ?
3 ответа
Как насчет следующего примера сценария?
Ход этого сценария выглядит следующим образом.
- Получить токен доступа из обновления токена.
- Создать сеанс.
- Загрузить файл по каждому куску. Максимальный размер фрагмента составляет 60 * 1024 * 1024 байта. Вы можете свободно менять.
Подробная информация - https://dev.onedrive.com/items/upload_large_files.htm.
Пример скрипта:
var fs = require('fs');
var request = require('request');
var async = require('async');
var client_id = "#####";
var redirect_uri = "#####";
var client_secret = "#####";
var refresh_token = "#####";
var file = "./sample.zip"; // Filename you want to upload.
var onedrive_folder = 'SampleFolder'; // Folder on OneDrive
var onedrive_filename = file; // If you want to change the filename on OneDrive, please set this.
function resUpload(){
request.post({
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
form: {
client_id: client_id,
redirect_uri: redirect_uri,
client_secret: client_secret,
grant_type: "refresh_token",
refresh_token: refresh_token,
},
}, function(error, response, body) { // Here, it creates the session.
request.post({
url: 'https://graph.microsoft.com/v1.0/drive/root:/' + onedrive_folder + '/' + onedrive_filename + ':/createUploadSession',
headers: {
'Authorization': "Bearer " + JSON.parse(body).access_token,
'Content-Type': "application/json",
},
body: '{"item": {"@microsoft.graph.conflictBehavior": "rename", "name": "' + onedrive_filename + '"}}',
}, function(er, re, bo) {
uploadFile(JSON.parse(bo).uploadUrl);
});
});
}
function uploadFile(uploadUrl) { // Here, it uploads the file by every chunk.
async.eachSeries(getparams(), function(st, callback){
setTimeout(function() {
fs.readFile(file, function read(e, f) {
request.put({
url: uploadUrl,
headers: {
'Content-Length': st.clen,
'Content-Range': st.cr,
},
body: f.slice(st.bstart, st.bend + 1),
}, function(er, re, bo) {
console.log(bo);
});
});
callback();
}, st.stime);
});
}
function getparams(){
var allsize = fs.statSync(file).size;
var sep = allsize < (60 * 1024 * 1024) ? allsize : (60 * 1024 * 1024) - 1;
var ar = [];
for (var i = 0; i < allsize; i += sep) {
var bstart = i;
var bend = i + sep - 1 < allsize ? i + sep - 1 : allsize - 1;
var cr = 'bytes ' + bstart + '-' + bend + '/' + allsize;
var clen = bend != allsize - 1 ? sep : allsize - i;
var stime = allsize < (60 * 1024 * 1024) ? 5000 : 10000;
ar.push({
bstart : bstart,
bend : bend,
cr : cr,
clen : clen,
stime: stime,
});
}
return ar;
}
resUpload();
В моем окружении это работает нормально. Я мог бы загрузить файл 100 МБ в OneDrive, используя этот скрипт. Если это не работает в вашей среде, не стесняйтесь, сообщите мне.
Это ES6-версия решения Tanaike.
const fs = require('fs')
const promisify = require('promisify')
const readFile = promisify(fs.readFile)
const uploader = async function(messageId) {
// const client = <setup your microsoft-client-here>
const address = '/path/to/file_name.jpg'
const name = 'file_name.jpg'
const stats = fs.statSync(address)
const size = stats['size']
const uploadSession = { AttachmentItem: { attachmentType: 'file', name, size } }
let location = ''
function getparams() {
const chSize = 10
const mega = 1024 * 1024
const sep = size < (chSize * mega) ? size : (chSize * mega) - 1
const arr = []
for (let i = 0; i < size; i += sep) {
const bstart = i
const bend = ((i + sep - 1) < size) ? (i + sep - 1) : (size - 1)
const cr = 'bytes ' + bstart + '-' + bend + '/' + size
const clen = (bend != (size - 1)) ? sep : (size - i)
const stime = size < (chSize * mega) ? 5000 : 10000
arr.push({ bstart, bend, cr, clen, stime })
}
return arr
}
async function uploadFile(url) {
const params = getparams()
for await (const record of params) {
const file = await readFile(address)
const result = await request({
url,
method: 'PUT',
headers: {
'Content-Length': record.clen,
'Content-Range': record.cr,
},
body: file.slice(record.bstart, record.bend + 1),
resolveWithFullResponse: true
})
location = (result.headers && result.headers.location) ? result.headers.location : null
// await new Promise(r => setTimeout(r, record.stime)) // If you need to add delay
}
}
const result = await client.api(`/me/messages/${messageId}/attachments/createUploadSession`).version('beta').post(uploadSession)
try {
await uploadFile(result.uploadUrl)
} catch (ex) {
console.log('ex.error:', ex.error)
console.log('ex.statusCode:', ex.statusCode)
await request.delete(result.uploadUrl)
}
return location
}
const fs = require('fs');
const axios = require('axios');
const client_id = 'face200d-b297-4a5a-8207-1cc297581a57'; // Your client ID
const client_secret = 'vOg8Q~wrSvUCwBbm6SfAs3QW4BM.VyTWHJQPKcfl'; // Your client secret
const refresh_token = '0.AX0ApesmMDcfP0GovwRmt8Axyw0gzvqXslpKggccwpdYGle1AF4'; // Your refresh token
const redirect_uri = 'http://localhost:3000/'; // Your redirect URI
const accessTokenFilePath = './access_token.json';
async function refreshAccessToken() {
try {
const refreshResponse = await axios.post('https://login.microsoftonline.com/common/oauth2/v2.0/token', null, {
params: {
client_id: client_id,
client_secret: client_secret,
refresh_token: refresh_token,
redirect_uri: redirect_uri,
grant_type: 'refresh_token'
}
});
const newAccessToken = refreshResponse.data.access_token;
fs.writeFileSync(accessTokenFilePath, JSON.stringify({ access_token: newAccessToken }));
return newAccessToken;
} catch (error) {
console.error('Error refreshing access token:', error.message);
throw error;
}
}
async function uploadFileToOneDrive(filePath, accessToken) {
try {
const fileStats = fs.statSync(filePath);
const fileSize = fileStats.size;
// Create upload session
const url = 'https://graph.microsoft.com/v1.0/me/drive/root:/envato';
const fileName = filePath.split('/').pop();
const uploadSessionResponse = await axios.post(`${url}/${fileName}:/createUploadSession`, null, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
const uploadUrl = uploadSessionResponse.data.uploadUrl;
// Upload file in chunks
const chunkSize = 5 * 1024 * 1024; // 5MB chunk size
let offset = 0;
while (offset < fileSize) {
const chunk = fs.readFileSync(filePath, {
encoding: null,
start: offset,
end: offset + chunkSize - 1
});
const range = `bytes ${offset}-${offset + chunk.length - 1}/${fileSize}`;
console.log(`Uploading range ${range}...`);
await axios.put(uploadUrl, chunk, {
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Length': chunk.length,
'Content-Range': range
}
});
offset += chunk.length;
}
console.log('File uploaded successfully');
return true;
} catch (error) {
console.error('Error uploading file to OneDrive:', error.message);
return false;
}
}
(async () => {
try {
const accessTokenData = fs.readFileSync(accessTokenFilePath, 'utf8');
const { access_token: accessToken } = JSON.parse(accessTokenData);
const success = await uploadFileToOneDrive('./sun-europe-trees-woods-yellow-above-natural-2023-02-27-20-26-28-utc.mp4', accessToken);
if (!success) {
const newAccessToken = await refreshAccessToken();
await uploadFileToOneDrive('./sun-europe-trees-woods-yellow-above-natural-2023-02-27-20-26-28-utc.mp4', newAccessToken);
}
} catch (error) {
console.error('Error:', error.message);
}
})();
Этот код загружает только файлы размером менее 150 МБ, как я могу загрузить файлы большего размера