質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

解決済

C#のwebRequestで複数のファイルをPOST送信したい。

s.s
s.s

総合スコア13

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。

1回答

0評価

0クリップ

387閲覧

投稿2022/06/03 04:31

編集2022/06/06 09:14

http://xxxx.xxx.xx.xx/filedataへ複数のファイル送信を行いたいのですが、うまくいきません。

以下のサイトを参考にしました。
https://ouipanda.hatenablog.com/entry/20090716/1247757511

データ受信側はDjangoRestFrameWorkで作成されています。

Postmanでhttp://xxxx.xxx.xx.xx/filedataへfomr-dataのkeyとValueを設定し、POSTしたところなんの問題もなく
送信&受信する事が出来ました。

パラメータはこんな感じです。
{
"id": "",
"title": "",
"pdf_file": "",
"csv_file": "",
}

ファイルを一つだけPOSTする場合は問題なく行えるのですが二つともファイルを送るとなると上手く行きません。

↓実際のコード

string url = "http://localhost:8000/api/filedata/"; List<string> files = new List<string>(); files.Add("C:\\file\TEST_BOOK1.csv"); files.Add("C:\\file\TEST.pdf"); List<string> fileNames = new List<string>(); fileNames.Add("pdf_file"); fileNames.Add("csv_file"); string tick = Environment.TickCount.ToString(); System.Text.Encoding enc = System.Text.Encoding.UTF8; WebRequest req = WebRequest.Create(url); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + tick; byte[] boundary = enc.GetBytes("--" + tick); byte[] crlf = enc.GetBytes("\r\n"); List<byte[]> headers = new List<byte[]>(); string header = ""; //ヘッダの作成とデータサイズの計算 long contentLen = 0; for (int i = 0; i < files.Count; i++) { //ヘッダ header = "--" + tick + "\r\n" + "Content-Disposition: form-data; name=\"" + fileNames[i] + i.ToString() + "\"; filename=\"" + Path.GetFileName(files[i]) + "\"\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Transfer-Encoding: binary\r\n\r\n"; headers.Add(enc.GetBytes(header)); //1ファイルごとのデータサイズ contentLen += headers[i].Length + new FileInfo(files[i]).Length; } //全体のデータサイズ req.ContentLength = contentLen + ((boundary.Length + crlf.Length + crlf.Length) * files.Count) + boundary.Length; //送信 using (Stream reqStream = req.GetRequestStream()) { for (int i = 0; i < files.Count; i++) { //送信ファイル using (FileStream fs = new FileStream(files[i], FileMode.Open, FileAccess.Read)) { //ヘッダ reqStream.Write(boundary, 0, boundary.Length); reqStream.Write(crlf, 0, crlf.Length); reqStream.Write(headers[i], 0, headers[i].Length); //ファイル内容 byte[] buf = new byte[0x1000]; int readSize = 0; while (true) { readSize = fs.Read(buf, 0, buf.Length); if (readSize == 0) break; reqStream.Write(buf, 0, readSize); } reqStream.Write(crlf, 0, crlf.Length); } } reqStream.Write(boundary, 0, boundary.Length); WebResponse res = req.GetResponse(); } }

追記

上手く行かない→

--boundary Content-Disposition: form-data; name="フォーム1"; filename="ファイル1" Content-Type: application/octet-stream Content-Transfer-Encoding: binary --boundary Content-Disposition: form-data; name="フォーム2"; filename="ファイル2" Content-Type: application/octet-stream Content-Transfer-Encoding: binary

というようにヘッダーの内容を記述し、送信したときに。
フォーム1に指定のファイルがPOSTされることは確認できるのですが、フォーム2へのPOSTが確認できない。
フォーム2への送信処理がとばされているのかと思ったのですが、Fiddlerを使い、内容を確認したところそういうわけでは無さそうです。

Postmanで送信したときの内容とプログラムから送信したときの内容を見比べてみました。
同じcsvファイルをPOSTしているのは確認がしやすいようにです、ファイル形式が違うため上げることが出来ないなどはありません。

Postmanの方は末尾に"--"が付いていますが、これは処理に関係あるのでしょうか?

以下 プログラムから送信したときの内容

--96403343 Content-Disposition: form-data; name="title" テスト --96403343 Content-Disposition: form-data; name="user" test --96403343 Content-Disposition: form-data; name="category" 1 --96403343 Content-Disposition: form-data; name="checked" False --96403343 Content-Disposition: form-data; name="pdf_file"; filename="Book1.csv" Content-Type: application/octet-stream Content-Transfer-Encoding: binary 11818818 18118 99999 --96403343 Content-Disposition: form-data; name="csv_file"; filename="Book1.csv" Content-Type: application/octet-stream Content-Transfer-Encoding: binary 11818818 18118 99999 --96403343

以下Postmanから送信したときの内容

----------------------------228829904362102449550779 Content-Disposition: form-data; name="title" test114 ----------------------------228829904362102449550779 Content-Disposition: form-data; name="csv_file"; filename="Book1.csv" Content-Type: text/csv 11818818 18118 99999 ----------------------------228829904362102449550779 Content-Disposition: form-data; name="pdf_file"; filename="Book1.csv" Content-Type: text/csv 11818818 18118 99999 ----------------------------228829904362102449550779--

コードの方も少し変えました

//送信先のURL string url = "http://localhost:8000/api/filedata/"; //送信対象のCSVファイルのパスと名前 string filePath = "C:\\tmp_file\\nest1\\Book1.csv"; string fileName = Path.GetFileName(filePath); //送信対象のPDFファイルのパスと名前 string pdffilePath = "C:\\tmp_file\\nest1\\Book1.csv"; string pdffileName = Path.GetFileName(pdffilePath); //パラメータ設定 string title = "テスト"; string user = "test"; // int category = 1; bool check = false; // string tick = Environment.TickCount.ToString(); System.Text.Encoding enc = System.Text.Encoding.UTF8; //WebRequestの生成 WebRequest req = WebRequest.Create(url); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + tick; byte[] boundary = enc.GetBytes("--" + tick); byte[] crlf = enc.GetBytes("\r\n"); List<byte[]> headers = new List<byte[]>(); //全体のヘッダー string postheader = "--" + tick + "\r\n" + "Content-Disposition: form-data; name=\"title\"\r\n\r\n" + title + "\r\n" + "--" + tick + "\r\n" + "Content-Disposition: form-data; name=\"user\"\r\n\r\n" + user + "\r\n" + "--" + tick + "\r\n" + "Content-Disposition: form-data; name=\"category\"\r\n\r\n" + category + "\r\n" + "--" + tick + "\r\n" + "Content-Disposition: form-data; name=\"checked\"\r\n\r\n" + check + "\r\n"; //ヘッダの作成とデータサイズの計算 long contentLen = 0; contentLen += enc.GetBytes(postheader).Length; string pdfheader = "Content-Disposition: form-data; name=\"pdf_file\"; filename=\"" + pdffileName + "\"\r\n" + "Content-Type: text/csv\r\n\r\n"; contentLen += boundary.Length + crlf.Length + enc.GetBytes(pdfheader).Length + new FileInfo(pdffilePath).Length + crlf.Length; string csvheader = "Content-Disposition: form-data; name=\"csv_file\"; filename=\"" + fileName + "\"\r\n" + "Content-Type: text/csv\r\n\r\n" + "--" + tick + "--\r\n"; contentLen += boundary.Length + crlf.Length + enc.GetBytes(csvheader).Length + new FileInfo(filePath).Length;// + crlf.Length; //全体のデータサイズ req.ContentLength = contentLen + boundary.Length; //送信 using (Stream reqStream = req.GetRequestStream()) { //全体のヘッダ reqStream.Write(enc.GetBytes(postheader), 0, enc.GetBytes(postheader).Length); using (FileStream pdfFs = new FileStream(pdffilePath, FileMode.Open, FileAccess.Read)) { //pdf部ヘッダ reqStream.Write(boundary, 0, boundary.Length); reqStream.Write(crlf, 0, crlf.Length); reqStream.Write(enc.GetBytes(pdfheader), 0, enc.GetBytes(pdfheader).Length); //ファイル内容 byte[] pdfbuf = new byte[0x1000]; int pdfreadSize = 0; while (true) { pdfreadSize = pdfFs.Read(pdfbuf, 0, pdfbuf.Length); if (pdfreadSize == 0) break; reqStream.Write(pdfbuf, 0, pdfreadSize); } reqStream.Write(crlf, 0, crlf.Length); } using (FileStream csvFs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { //csv部ヘッダ reqStream.Write(boundary, 0, boundary.Length); reqStream.Write(crlf, 0, crlf.Length); reqStream.Write(enc.GetBytes(csvheader), 0, enc.GetBytes(csvheader).Length); //ファイル内容 byte[] csvbuf = new byte[0x1000]; int csvreadSize = 0; while (true) { csvreadSize = csvFs.Read(csvbuf, 0, csvbuf.Length); if (csvreadSize == 0) break; reqStream.Write(csvbuf, 0, csvreadSize); } reqStream.Write(crlf, 0, crlf.Length); }   reqStream.Write(boundary, 0, boundary.Length);

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

SurferOnWww

2022/06/03 07:37 編集

「うまくいきません」と言うだけでは情報不足です。具体的にどのような結果になるのかを書いてください。 Postman で期待通りの結果になるなら、Fiddler を使ってその時の要求ヘッダ・コンテンツがどのようになっているかと、「うまくいきません」という場合とを比較してみてはいかがですか。そこに解決のためのヒントが見つかるのではないかと思います。
SurferOnWww

2022/06/03 05:03

WebRequest の使用は必須ですか? HttpClient を使うことはできますか?
SurferOnWww

2022/06/03 06:51

> Postmanの方は末尾に"--"が付いていますが、これは処理に関係あるのでしょうか? ざっと見た限りでは気になる違いはそこぐらいでしょうか。 仕様かどうか、それが影響しているのかどうかは分かりませんが、自分がブラウザ (Chrome)、HttpClient、および https://dobon.net/vb/dotnet/internet/webrequestpost.html を参考に作った HttpWebRequest / HttpWebResponse を使ったコードでは一番最後の boundary には末尾に -- を追加しています。
s.s

2022/06/03 07:20

ありがとうございます、無事解決する事が出来ました。 SurferOnWwwさんから”Fidller を使って~”という提案があったおかけです、何をしているか(送っているか)という詳細を知るのは重要ですね・・・勉強になりました。
SurferOnWww

2022/06/03 09:01

HttpClient を使うと自分でコードを書いて boundary を設定する必要ななく、自動的にやってくれます。次の機会には HttpClient の使用を検討されてはいかがでしょう。
s.s

2022/06/06 00:14

そのような方法もあるのですね、自分の勉強不足を痛感致します・・・ この度は有難うございました。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

HttpWebRequest

HttpWebRequestとは.NETにおけるクラスであり、WebRequestクラスをHTTPに導入するものです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

POST

POSTはHTTPプロトコルのリクエストメソッドです。ファイルをアップロードしたときや入力フォームが送信されたときなど、クライアントがデータをサーバに送る際に利用されます。