【问题标题】:Microsoft Graph's createUploadSession, Content-Range Header errorMicrosoft Graph 的 createUploadSession、Content-Range Header 错误
【发布时间】:2020-07-08 01:01:51
【问题描述】:

我正在尝试将 Microsoft Graph API 的 createUploadSession 端点与 JavaScript SDK 一起使用,并尝试使用刚刚超过 3MB 的小文件来测试上传。每当发送PUT 请求时,我都会收到以下错误响应:

{
  "error": {
     "code": "InvalidContentRangeHeader",
     "message": "Invalid Content-Range header."
  }
}

我正在尝试一次发送整个文件,所以请求如下所示:

  const uploadSession = await client
    .api(`/me/messages/${messageId}/attachments/createUploadSession`)
    .version('beta')
    .post({
      AttachmentItem: {
        attachmentType: 'file',
        name: attachment.name,
        size: attachment.size,
      },
    });

  const res = await fetch(uploadSession.uploadUrl, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/octet-stream',
      'Content-Range': `bytes 0-${attachment.size - 1}/${attachment.size}`,
      'Content-Length': attachment.size,
    },
    body: attachment.contentBytes,
  });

  const json = await res.json();
  return json;

这里有什么我遗漏的吗?如果我理解正确,给出完整的范围应该传递整个文件。

【问题讨论】:

    标签: javascript fetch microsoft-graph-api microsoft-graph-mail http-content-range


    【解决方案1】:

    问题可能已经过时,因为您使用的是测试版,并且 UploadSessions 现在是核心功能的一部分:https://docs.microsoft.com/en-us/graph/outlook-large-attachments

    无论如何,我仍然决定在 JS 中分享我的工作实现(TypeScript,更正确),因为关于这个主题的大多数问题都是针对C#

    在创建uploadSession 后,我没有尝试立即上传整个文件(尽管文档指出这是可能的),但决定按照他们的建议将整个文件以 4MB 块的形式上传到PUT

    const BYTE_RANGE = 4e6
    
    ...
    
    // Send large attachments using an uploadSession
    private async _uploadLargeAttachments(
        attachments: IMSLargeFileAttachment[],
        messageId: string,
        clientInstance: Client
    ): Promise<string[]> {
        return Promise.all(
            attachments.map(async (attachment) => {
                const { attachmentType, name, size } = attachment
                const uploadSession: UploadSession = await clientInstance
                    .api(`/me/messages/${messageId}/attachments/createUploadSession`)
                    .post({
                        AttachmentItem: { attachmentType, name, size },
                    })
    
                    if (!uploadSession.uploadUrl) {
                        // You may also want to throw an error here
                        return null
                    }
    
                const fragmentsTotal = Math.ceil(size / BYTE_RANGE)
                let i = 0
                let bytesRemaining = size
    
                while (i < fragmentsTotal) {
                    const step = (i + 1) * BYTE_RANGE
                    const from = i * BYTE_RANGE
                    const to = bytesRemaining > BYTE_RANGE ? step - 1 : size - 1
                    bytesRemaining = Math.max(size - step, 0)
    
                    const res = await fetch(uploadSession.uploadUrl, {
                        method: 'PUT',
                        headers: {
                            'Content-Type': 'application/octet-stream',
                            'Content-Length': `${to - from + 1}`,
                            'Content-Range': `bytes ${from}-${to}/${size}`,
                        },
                        body: attachment.body.slice(from, to + 1), // the 2nd slice arg is not inclusive
                    })
    
                    // The final response should have the 'Location' header with a long URL,
                    // from which you can extract the attachment ID
                    if (res.status === 201 && res.headers.has('Location')) {
                        return res.headers.get('Location')
                    }
                    i++
                }
            }).filter((it) => Boolean(it))
        )
    }
    

    希望这可以帮助任何与我一样挣扎的人更快地达到他们的目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-25
      • 2019-08-11
      • 1970-01-01
      相关资源
      最近更新 更多