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 ответа

Решение

Как насчет следующего примера сценария?

Ход этого сценария выглядит следующим образом.

  1. Получить токен доступа из обновления токена.
  2. Создать сеанс.
  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 МБ, как я могу загрузить файлы большего размера

Другие вопросы по тегам