.NET FrameworkのHttpClientを利用した、コンテンツアップロードAPIへのPOSTについて
現在、C#(.NET Framework)のHttpClientから、コンテンツアップロードAPIを利用し画像ファイルのアップロードを行うプログラムを作成しています。
ファイルをPostする際にエラーが返され、1日ほど奮闘しましたが解決できなかったため、質問させていただきます。
【やりたいこと】
C#からHttpClientを用いて画像ファイルのアップロードを行いたい。
【現象】
C#のHttpClientにて、コンテンツアップロードAPIに対して画像ファイルをPostしているが、504がレスポンスとして返される。
また、Windows 10 の curl.exe によるアップロードを試したところ、こちらはアップロードに成功した。
【環境】
OS: Windows 10 Pro
C# バージョン: 7.3
.NET Framework バージョン: 4.6.1
【調査結果】
C#のHttpClientとcurlのリクエストをFiddlerで確認したところ、ほとんど違いは見られませんでした。
違いとしては、curlのヘッダには "Connection: Keep-Alive" が設定されていましたが、C#からPostした場合には含まれていませんでした。
ただ、調べた限りではHttpClientについてもデフォルトでKeep-Aliveが有効化されるとのことでした。(とはいえヘッダーに含まれないのは怪しいので、ここを疑っています)
それぞれのヘッダーの内容は以下となります。
[C#] Httpリクエストヘッダー
Accept: */*
User-Agent: プログラム名
consumerKey: 発行されたコンシューマキー
authorization: Bearer 発行されたアクセストークン
x-works-apiid: 発行されたAPIID
Content-Type: multipart/form-data; boundary="f266990d-6b81-4cb2-a892-70b7499909e9"
Host: storage.worksmobile.com
Content-Length: 8302
Expect: 100-continue
[C#] コンテンツヘッダー
Content-Disposition: form-data; name="resourceName"; filename="ファイル名.jpg"
Content-Type: image/jpeg
[curl] Httpリクエストヘッダー
Host: storage.worksmobile.com
User-Agent: curl/7.55.1
Accept: */*
Connection: Keep-Alive
consumerKey: 発行されたコンシューマキー
authorization: Bearer 発行されたアクセストークン
x-works-apiid: 発行されたAPIID
Content-Length: 8288
Expect: 100-continue
Content-Type: multipart/form-data; boundary=------------------------04f1f228ec120c0d
[curl] コンテンツヘッダー
Content-Disposition: form-data; name="resourceName"; filename="ファイル名.jpg"
Content-Type: image/jpeg
以上です。
初歩的な事柄かもしれませんが、ご助言お願いいたします。
投稿に新しいコメントが追加されましたら通知を送信します。
コメント4
업데이트 된 답글입니다.
赤軸 投稿者
上記につきまして、その後も調査を行いましたがこれといった成果は得られませんでした。
結局HttpClientの使用を諦め、HttpWebRequestを使用したところ正常にアップロードすることができました。
差異としては、やはりKeep-Aliveの有無くらいしかなさそうですが、HttpClientからPostした際に付与されない理由については不明です。
(.NET Frameworkのソースを読めばわかりそうですが。)
2019.12.04
업데이트 된 답글입니다.
LINE WORKS 公式アカウント
HttpClient での動作は確認しておりませんが、こちらで動作を確認したコードでは「"Connection", "keep-alive"」設定の有無による影響はありませんでした。
ご参考ください。
2019.12.05
업데이트 된 답글입니다.
赤軸 投稿者
>HttpClient での動作は確認しておりませんが、こちらで動作を確認したコードでは「"Connection", "keep-alive"」設定の有無による影響はありませんでした。
ご確認いただきありがとうございます。
要求ヘッダーの差異がKeep-Aliveのみでしたので疑っていましたが、こちらが直接の原因ではないようですね。
またどこかで調査してみようと思います。
ご回答いただき、ありがとうございました。
2019.12.09
업데이트 된 답글입니다.
Koshi検証用
同じ事象で困っている方もおられると思うので投稿します。
原因はヘッダーのboundaryが「"」で囲まれていることです。
---------------------------------------------------
・Content-Type: multipart/form-data; boundary="f266990d-6b81-4cb2-a892-70b7499909e9" ←NG
・Content-Type: multipart/form-data; boundary=------------------------04f1f228ec120c0d ←OK
---------------------------------------------------
これはLineWorksのAPIの障害と思われるので改修をお願いします。
APIの処理でリクエストヘッダーからboundaryを取り出すときに["]も含めて取得しているのだと思います。
そのためコンテンツ内のboundary(こちらは「"」で囲われません)とイコールにならないため
エラー判定されているのだと推測します。
サンプルコードを以下に記載しておきます。
```C#
string ApiId = "XXX";
string ConsumerKey = "XXX";
string Token = "XXX";
string URL = "http://storage.worksmobile.com/openapi/message/upload.api";
string Path = "XXX.png";
HttpClient Client = new HttpClient();
using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, URL))
using (var dataContent = new MultipartFormDataContent())
using (var fileStream = File.OpenRead(Path))
using (var streamContent = new StreamContent(fileStream))
{
requestMessage.Headers.Add("consumerKey", ConsumerKey);
requestMessage.Headers.Add("Authorization", Token);
requestMessage.Headers.Add("x-works-apiid", ApiId);
// HTTP応答のContent-Typeから「boundary」の値を取得、「"」を削除して再設定
var boundary = dataContent.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
boundary.Value = boundary.Value.Replace("\"", string.Empty);
streamContent.Headers.ContentDisposition =
new ContentDispositionHeaderValue("form-data")
{
Name = "\"resourceName\"",
FileName = string.Format("\"{0}\"", new FileInfo(Path).Name)
};
streamContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
dataContent.Add(streamContent);
requestMessage.Content = dataContent;
var response = Client.SendAsync(requestMessage).Result;
}
```
2021.09.08
まだ、解決できませんか?
今すぐ実際に使用しているLINE WORKSユーザーに質問してみましょう。