OneDrive API Node.js - 无法使用:/ createUploadSession内容范围错误

时间:2017-08-14 22:42:30

标签: node.js onedrive http-content-range

我的问题是我无法上传大于4MB的文件所以我根据createuploadsession使用了createuploadsession

我成功从createuploadsession响应中获取了uploadUrl值。现在我尝试使用此代码发出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);
    }); 
}); 

但如果我尝试

,我会得到“Invalid Content-Range标头值”的响应
'Content-Range': 'bytes 0-' + f.length
//or
'Content-Range': 'bytes 0-' + f.length + '/' + f.length

我会得到同样的答复 此外,我不想将我的文件分块,我只想在1run上传我的文件。有没有人有用于从createuploadsession响应上传文件到uploadUrl的示例代码。另外,在我上传大于4mb的文件或者有其他方法之前,我是否真的需要先获得此上传文件?

2 个答案:

答案 0 :(得分:2)

如何关注示例脚本?

此脚本的流程如下。

  1. 从刷新令牌中检索访问令牌。
  2. 创建sesssion。
  3. 按每个块上传文件。当前块大小为max,即60 * 1024 * 1024字节。你可以自由改变。
  4. 详细信息为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 MB文件上传到OneDrive。如果这在您的环境中无效,请随时告诉我。

答案 1 :(得分:0)

这是Tanaike解决方案的ES6版本。

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
}