OneDrive REST API - 上传块时请求的范围错误
OneDrive REST API - Requested Range Error While Uploading Chunk
我一直在尝试按照此文档 (https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createuploadsession?view=odsp-graph-online) 通过 HTTP 请求将文件上传到我的 OneDrive,但没有成功。我汇总了以下步骤 (Authentication, folder creation for the file, create an upload session) 但是当我尝试最后一步时,字节上传到创建的 session,我在第二个 PUT 请求中收到此错误:
请求范围不满足{"error":{"code":"invalidRange","message":"分片上传时乐观并发失败"}}
这是我的代码:
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
//Chunk Calculation
int TotalSize = FileByteArray.Length;
int AcumulativeSize = 0;
int ChunkSize = 327680;
int ChunkBuffer = ChunkSize;
int ChunkNumber = TotalSize / ChunkSize;
int ChunkLeftover = TotalSize - ChunkSize * ChunkNumber;
int ChunkCounter = 0;
while (true)
{
if (ChunkNumber == ChunkCounter)
{
ChunkSize = ChunkLeftover;
}
byte[] ChunkData = FileByteArray.Skip(ChunkBuffer * ChunkCounter).Take(ChunkSize).ToArray();
AcumulativeSize += ChunkData.Length;
//PUT Upload of Chunk
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {AcumulativeSize - ChunkSize}-{AcumulativeSize - 1}/{TotalSize}";
OutlookClient.DefaultRequestHeaders.Clear();
OutlookClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", ChunkSize.ToString());
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.PutAsync(UploadEndpoint, new ByteArrayContent(ChunkData));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
if (ChunkNumber == ChunkCounter)
{
break;
}
ChunkCounter++;
}
}
}
也许我遗漏了什么。我只在第一个 PUT 请求中收到 SUCCESS 消息,其他人总是给我上述错误。这是我发送的 headers 的错误图片。 Image
非常感谢您的帮助,感谢您阅读到这里。
编辑:
在修改请求的 header 配置并更改块的创建方式后,它开始工作了。
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
using MemoryStream FileStream = new MemoryStream(FileByteArray);
//Chunk Calculation
int ChunkSize = 320 * 1024;
int ChunkRemaining = 0;
byte[] ByteBuffer = new byte[ChunkSize];
int BytesRead = 0;
while ((BytesRead = FileStream.Read(ByteBuffer, 0, ByteBuffer.Length)) > 0)
{
if (BytesRead < ChunkSize)
{
byte[] LastBuffer = new byte[BytesRead];
Buffer.BlockCopy(ByteBuffer, 0, LastBuffer, 0, BytesRead);
ByteBuffer = new byte[BytesRead];
ByteBuffer = LastBuffer;
}
try
{
OutlookClient.DefaultRequestHeaders.Clear();
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {ChunkRemaining}-{ChunkRemaining + ByteBuffer.Length - 1}/{FileByteArray.Length}";
HttpRequestMessage MicrosoftResponseMessage = new HttpRequestMessage()
{
Content = new ByteArrayContent(ByteBuffer),
RequestUri = new Uri(UploadEndpoint),
Method = HttpMethod.Put,
};
MicrosoftResponseMessage.Content.Headers.Add("Content-Length", ByteBuffer.Length.ToString());
MicrosoftResponseMessage.Content.Headers.Add("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.SendAsync(MicrosoftResponseMessage);
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
ChunkRemaining += ByteBuffer.Length;
if (ChunkRemaining == FileByteArray.Length)
{
Console.WriteLine("COMPLETED");
}
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
}
catch (Exception Exception)
{
Console.WriteLine(Exception.Message);
break;
}
}
}
}
请注意,如果客户端发送服务器已收到的片段失败,服务器将响应 HTTP 416 Requested Range Not Satisfiable。您可以 request upload status 获取更详细的缺失范围列表。显然 content-range 和 content-length 是问题所在。您将 header 配置从 HttpClient 更改为 HttpRequestMessage,它现在运行良好。
我一直在尝试按照此文档 (https://docs.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createuploadsession?view=odsp-graph-online) 通过 HTTP 请求将文件上传到我的 OneDrive,但没有成功。我汇总了以下步骤 (Authentication, folder creation for the file, create an upload session) 但是当我尝试最后一步时,字节上传到创建的 session,我在第二个 PUT 请求中收到此错误:
请求范围不满足{"error":{"code":"invalidRange","message":"分片上传时乐观并发失败"}}
这是我的代码:
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
//Chunk Calculation
int TotalSize = FileByteArray.Length;
int AcumulativeSize = 0;
int ChunkSize = 327680;
int ChunkBuffer = ChunkSize;
int ChunkNumber = TotalSize / ChunkSize;
int ChunkLeftover = TotalSize - ChunkSize * ChunkNumber;
int ChunkCounter = 0;
while (true)
{
if (ChunkNumber == ChunkCounter)
{
ChunkSize = ChunkLeftover;
}
byte[] ChunkData = FileByteArray.Skip(ChunkBuffer * ChunkCounter).Take(ChunkSize).ToArray();
AcumulativeSize += ChunkData.Length;
//PUT Upload of Chunk
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {AcumulativeSize - ChunkSize}-{AcumulativeSize - 1}/{TotalSize}";
OutlookClient.DefaultRequestHeaders.Clear();
OutlookClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", ChunkSize.ToString());
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.PutAsync(UploadEndpoint, new ByteArrayContent(ChunkData));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
if (ChunkNumber == ChunkCounter)
{
break;
}
ChunkCounter++;
}
}
}
也许我遗漏了什么。我只在第一个 PUT 请求中收到 SUCCESS 消息,其他人总是给我上述错误。这是我发送的 headers 的错误图片。 Image
非常感谢您的帮助,感谢您阅读到这里。
编辑:
在修改请求的 header 配置并更改块的创建方式后,它开始工作了。
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
using MemoryStream FileStream = new MemoryStream(FileByteArray);
//Chunk Calculation
int ChunkSize = 320 * 1024;
int ChunkRemaining = 0;
byte[] ByteBuffer = new byte[ChunkSize];
int BytesRead = 0;
while ((BytesRead = FileStream.Read(ByteBuffer, 0, ByteBuffer.Length)) > 0)
{
if (BytesRead < ChunkSize)
{
byte[] LastBuffer = new byte[BytesRead];
Buffer.BlockCopy(ByteBuffer, 0, LastBuffer, 0, BytesRead);
ByteBuffer = new byte[BytesRead];
ByteBuffer = LastBuffer;
}
try
{
OutlookClient.DefaultRequestHeaders.Clear();
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {ChunkRemaining}-{ChunkRemaining + ByteBuffer.Length - 1}/{FileByteArray.Length}";
HttpRequestMessage MicrosoftResponseMessage = new HttpRequestMessage()
{
Content = new ByteArrayContent(ByteBuffer),
RequestUri = new Uri(UploadEndpoint),
Method = HttpMethod.Put,
};
MicrosoftResponseMessage.Content.Headers.Add("Content-Length", ByteBuffer.Length.ToString());
MicrosoftResponseMessage.Content.Headers.Add("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.SendAsync(MicrosoftResponseMessage);
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
ChunkRemaining += ByteBuffer.Length;
if (ChunkRemaining == FileByteArray.Length)
{
Console.WriteLine("COMPLETED");
}
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
}
catch (Exception Exception)
{
Console.WriteLine(Exception.Message);
break;
}
}
}
}
请注意,如果客户端发送服务器已收到的片段失败,服务器将响应 HTTP 416 Requested Range Not Satisfiable。您可以 request upload status 获取更详细的缺失范围列表。显然 content-range 和 content-length 是问题所在。您将 header 配置从 HttpClient 更改为 HttpRequestMessage,它现在运行良好。