私はWindowsに組み込まれているクライアントアプリケーションが私が理解できない理由で失敗しているため、OneDriveデスクトップクライアントアプリケーションを開発しています。私はC#でHttpClient
経由でREST APIを使用しています。OneDrive API再開可能なアップロードURLが応答しない
onedriveエンドポイントへのすべてのリクエストはうまく動作します(ダウンロード、小さなファイルのアップロードなど)。大きなファイルのアップロードは、最近まで(約2日前まで)正常に機能しました。アップロードセッションURLを取得してデータをアップロードしますが、2つのチャンクを正常にアップロードした後(202応答)、3番目の要求以降は(HttpClient
を介して)GET
のステータスを取得するかどうか、またはデータをアップロードするPUT
セッションを作成するためのPOST
はまだ動作します。
新しいClientId
を取得し、新しいMicrosoftアカウントにログインし、コードを既知の動作状態に戻し、gitリポジトリを再クローンしました。
PostManではセッションを作成してチャンクをアップロードし、この問題は発生しませんが、アプリケーションがOneDrive APIから取得するアップロードURLを取得して、PUT
のデータを試してみることができますPostManでは、サーバーは応答しません(要求が無効でない限り、時々私に知らせる)。この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
すべてはコメントが何を言うんや名前が示唆するものを、メソッドやクラスの多くは私のものですから、明白ではないかもしれないことを説明するのはうれしいです。
私は何が起こっているのか全く分からず、助けていただければ幸いです。私は土曜日に学校に戻る前にこれをやろうとしており、もはやそれに取り組む時間はありません。
EDIT:しばらく待ってから、PostMan経由でアップロードURLを再度リクエストすることができます。
EDIT 2:私はもはやこのタイムアウト現象を郵便配達員に複製することはできません。アプリケーションからアップロードURLを取得したか、別のPostmanリクエストから取得したものであっても、アップロードがアプリケーションで停止しているかどうかに関わらず、私は郵便配達ですべてのフラグメントをアップロードすることができます。
EDIT 3:この応答しない動作は、コンテンツストリームを読み込む前に開始されます。
編集4: WireSharkのパケット情報を見ると、最初の2つのチャンクはほぼ同じですが、 "再送"パケットだけが3番目に表示されます。