我一直在开发一个OneDrive桌面客户端应用程序,因为内置在windows中的应用程序一直让我失望,原因我无法弄清楚。我通过一个C#在HttpClient
中使用REST。
所有对onedrive端点的请求都正常工作(下载、上传小文件等)。直到最近(大约两天前),上传大型文件的工作还不错。我获得上传会话URL并开始将数据上传到它,但是在成功地将两块数据上传到它之后(202个响应),第三个请求和超时(通过HttpClient
),无论是一个GET
获取状态,还是一个PUT
来上传数据。创建会话的POST
仍然有效。
我尝试过:获得一个新的ClientId
,登录到一个新的Microsoft帐户,将代码恢复到已知的工作状态,以及重新克隆git存储库。
在PostMan中,我可以完成创建会话和上传块的整个过程,而不会遇到这个问题,但是如果我将应用程序从OneDrive API检索的上传URL并试图在PostMan中将PUT
数据发送给它,服务器将不会响应(除非请求无效,它有时会告诉我)。对这个URL的后续GET
请求也没有响应。
下面是所有经过身份验证后转到OneDrive API的请求的日志:https://pastebin.com/qRrw2Sb5
以下是相关代码:
//first, create an upload session
var httpResponse = await _httpClient.StartAuthenticatedRequest(url, HttpMethod.Post).SendAsync(ct);
if (httpResponse.StatusCode != HttpStatusCode.OK)
{
return new HttpResult<IRemoteItemHandle>(httpResponse, null);
}
//get the upload URL
var uploadSessionRequestObject = await HttpClientHelper.ReadResponseAsJObjectAsync(httpResponse);
var uploadUrl = (string)uploadSessionRequestObject["uploadUrl"];
if (uploadUrl == null)
{
Debug.WriteLine("Successful OneDrive CreateSession request had invalid body!");
//TODO: what to do here?
}
//the length of the file total
var length = data.Length;
//setup the headers
var headers = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("Content-Length", ""),
new KeyValuePair<string, string>("Content-Range","")
};
JObject responseJObject;
//the response that will be returned
HttpResponseMessage response = null;
//get the chunks
List<Tuple<long, long>> chunks;
do
{
HttpResult<List<Tuple<long, long>>> chunksResult;
//get the chunks
do
{
chunksResult = await RetrieveLargeUploadChunksAsync(uploadUrl, _10MB, length, ct);
//TODO: should we delay on failure?
} while (chunksResult.Value == null);//keep trying to get thre results until we're successful
chunks = chunksResult.Value;
//upload each fragment
var chunkStream = new ChunkedReadStreamWrapper(data);
foreach (var fragment in chunks)
{
//setup the chunked stream with the next fragment
chunkStream.ChunkStart = fragment.Item1;
//the size is one more than the difference (because the range is inclusive)
chunkStream.ChunkSize = fragment.Item2 - fragment.Item1 + 1;
//setup the headers for this request
headers[0] = new KeyValuePair<string, string>("Content-Length", chunkStream.ChunkSize.ToString());
headers[1] = new KeyValuePair<string, string>("Content-Range", $"bytes {fragment.Item1}-{fragment.Item2}/{length}");
//submit the request until it is successful
do
{
//this should not be authenticated
response = await _httpClient.StartRequest(uploadUrl, HttpMethod.Put)
.SetContent(chunkStream)
.SetContentHeaders(headers)
.SendAsync(ct);
} while (!response.IsSuccessStatusCode); // keep retrying until success
}
//parse the response to see if there are more chunks or the final metadata
responseJObject = await HttpClientHelper.ReadResponseAsJObjectAsync(response);
//try to get chunks from the response to see if we need to retry anything
chunks = ParseLargeUploadChunks(responseJObject, _10MB, length);
}
while (chunks.Count > 0);//keep going until no chunks left
所有的东西都会做注释说什么或名字暗示什么,但是很多方法/类都是我自己的,所以我很乐意解释任何可能不明显的事情。
我完全不知道这是怎么回事,希望能得到任何帮助。我正试着在星期六回到学校之前把这件事做完,现在没有时间去做了。
编辑:等待一段时间后,可以通过PostMan再次向上传URL发出请求。
编辑2: i不能在邮递员中复制这种超时现象。无论我是从我的应用程序中获得上传URL,还是从另一个邮递员请求中获得,以及我的应用程序中的上传是否停止,我似乎都可以通过Postman上传我想要的所有片段。
编辑3:这种没有响应的行为在读取内容流之前就开始了。
编辑4:查看WireShark上的数据包信息,前两个块几乎是相同的,但是只有“重发”数据包出现在第三个块上。
发布于 2017-09-11 01:08:00
因此,经过3周的不同级别的测试,我终于发现了这个问题,这与OneDrive Graph
api几乎没有任何关系。问题是,在发出Http请求时,我使用的是HttpCompletionOption.ResponseHeadersRead
,而不是在发送下一个响应之前读取响应。这意味着HttpClient
阻止我发送更多的请求,直到我阅读了旧的回复。这很奇怪,因为它允许我在锁定之前发送两个请求。
https://stackoverflow.com/questions/45830398
复制相似问题