■86345 |
Re[4]: HttpClientでのmultipart/mixed送信 |
□投稿者/ 魔界の仮面弁士 -(2018/01/22(Mon) 11:29:31)
| ■No86343 (さえ さん) に返信
> foreach (var s in list)
「foreach (var s in files)」ですよね。
ところで、HttpClient には下記のような問題があるのでご注意を。
https://qiita.com/nskhara/items/b7c31d60531ffbe29537
> ***正常に動作するサンプルの送出データ***
> Content-Length: 13795
> ***自作C#の送出データ***
> Content-Length: 13793
要求ボディのサイズ(Content-Length ヘッダー)が 2 バイト違っていますが、
これは先頭の CR LF の有無によるものです。
VBA バージョンにおいて、その 冒頭の CR LF を削って送出した場合、
残念ながら No86325 で示したように
「ファイルがありません。アップロードしてください。」
が再現することになります。本来、冒頭の CR LF は無くても構わないはずなので、
このような動作になっているのは、Web API 側の実装に問題があるのだと推察します。
マルチパートな HTTP では、preamble (および epilogue) は
空で送信されるのが通例ですし、先頭が空の preamble である場合、
冒頭の CR LF は省略可能だと思うのですけれどね…。
https://www.ietf.org/rfc/rfc2046.txt
》multipart-body := [preamble CRLF]
》 dash-boundary transport-padding CRLF
》 body-part *encapsulation
》 close-delimiter transport-padding
》 [CRLF epilogue]
》
https://wiki.suikawiki.org/n/境界文字列
》古い版の MIME では一番最初の本体部分の前の境界でも
》--boundary の前の CRLF が必須とされていましたが、
》今日では不具合であったと考えられています。
> Shift_JISのcsvはUTF-8 に再エンコードして送出されているようでしたので、
PDF に記載された要求の例では
Content-Type: text/csv
となっているのに、VBA 実装では
Content-Type: text/csv; charset=utf-8
となっていますし、仕様か実装のいずれかが間違っていそう。
> バウンダリにダブルクォーテーションを付けない形で設定する方法はどうすればよいでしょうか。
VBA 版と同様、要求電文を自前で組み立てないと駄目かも。
以下、Task 化してませんが参考までに。
static void Main()
{
var files = new List<string>();
files.Add(@"C:\temp\A");
string url = @"http://model.app.lowenergy.jp/api/v1/ConvertToWebInput";
var webReq = System.Net.HttpWebRequest.CreateHttp(url);
webReq.Method = HttpMethod.Post.Method;
// var boundary = "================12345678987654321";
var boundary = "==" + Guid.NewGuid().ToString("D");
//バウンダリを quoted-string にすると失敗する
//webReq.ContentType = "multipart/mixed; boundary=\"" + boundary + "\"";
//バウンダリを token として表現する
webReq.ContentType = "multipart/mixed; boundary=" + boundary;
var mem = new MemoryStream();
var writer = new StreamWriter(mem, Encoding.UTF8);
foreach (var s in files)
{
// 最初のバウンダリであっても、\r\n を先導させないと失敗する
writer.Write("\r\n--" + boundary + "\r\n");
// ここは「name="A"」でも「name=A」でも構わない
writer.Write("Content-Disposition: mixed; name=" + Path.GetFileName(s) + "\r\n");
//writer.Write("Content-Disposition: mixed; name=\"" + Path.GetFileName(s) + "\"\r\n");
// Content-Type はもちろん必須だが、chaset の検査はされていない模様
// というか、そもそも "text/csv" 以外を指定しても動いてしまう
writer.Write("Content-Type: text/csv\r\n");
// CSV の文字コードは UTF-8 にしておく必要がある模様
// 使用可能な文字種(文字集合)は CP932 準拠?
writer.Write("\r\n" + File.ReadAllText(s));
}
writer.Write("\r\n--" + boundary + "--");
writer.Flush();
webReq.ContentLength = mem.Length;
mem.Position = 0;
var reqStm = webReq.GetRequestStream();
reqStm.Write(mem.ToArray(), 0, (int)mem.Length);
reqStm.Close();
writer.Dispose();
var res = webReq.GetResponse();
var resStream = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
string result = resStream.ReadToEnd();
resStream.Close();
res.Dispose();
Console.WriteLine(result);
} |
|