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

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

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

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

HTTPヘッダー

Hypertext Transfer Protocol(HTTP)の中のHTTPヘッダフィールドはHTTPの要求やレスポンスの機能しているパラメーターが含まれます。その要求もしくはレスポンスライン(メッセージの最初の一行)でメッセージヘッダを作ります。

C#

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

Q&A

解決済

4回答

12067閲覧

C# HttpWebResponseでcontentlengthの取得方法

dai49

総合スコア14

HTTP

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

HTTPヘッダー

Hypertext Transfer Protocol(HTTP)の中のHTTPヘッダフィールドはHTTPの要求やレスポンスの機能しているパラメーターが含まれます。その要求もしくはレスポンスライン(メッセージの最初の一行)でメッセージヘッダを作ります。

C#

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

1グッド

1クリップ

投稿2018/04/02 07:22

前提・実現したいこと

初めて質問させていただきます。
HttpWebReqestでGETリクエストし、レスポンスで返ってきたcontentlengthを取得したいのですが、-1になってしまいます。
MSDNを参照すると「Content-length ヘッダーが応答で設定されていない場合 ContentLength が-1 の値に設定します。」となってるのでそもそも取得できないということなのでしょうか?

完成イメージはGETリクエストで返ってくるstatuscodeやlength、dataなどのヘッダー情報取得、メッセージボディも取得してコンソールに出力させたいと考えています。

情報不足や不手際ありましたら申し訳ありません。
詳しい方ご教示お願いします。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

try
{
string streamBuffer = null;

httpWebRequest = WebRequest.CreateHttp(pUrl); httpWebRequest.UserAgent = "http client/1.1"; httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); long length = httpWebResponse.ContentLength; Stream dataStream = httpWebRequest.GetResponse().GetResponseStream(); Encoding encode = Encoding.GetEncoding("utf-8"); StreamReader streamReader = new StreamReader(dataStream, encode); streamBuffer = streamReader.ReadToEnd(); Console.WriteLine(streamBuffer + "\r\n" + "\r\n" + length); httpWebResponse.Close();

試したこと

HttpWebReqest.Method="HEAD"
で指定して複数のURLでリクエストしたところレスポンスが返ってくるURLと-1のURLがありました。
ただ、取得できたURLでもHttpWebReqest.Method="GET"に変えると-1になってしまいました。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

shikasama👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

MSDNを参照すると「Content-length ヘッダーが応答で設定されていない場合 ContentLength が-1 の値に設定します。」となってるのでそもそも取得できないということなのでしょうか?

検証したわけではないですが、それはサーバーが返す応答ヘッダに Content-Length が設定されてない場合、HttpWebResponse.ContentLength プロパティは -1 になるということだと思います。

つまり、HttpWebResponse.ContentLength プロパティで正しい値が取得できるか否かはサーバー次第で、サーバーが応答ヘッダに Content-Length を設定してくれればその値が取得できるはずです。

試しに、以下の記事のように WCF サービスのメソッドを HttpWebRequest / HttpWebResponse を利用して呼び出した場合で検証してみました。

HttpWebRequest で WCF サービスを呼出
http://surferonwww.info/BlogEngine/post/2017/03/26/request-wcf-service-method-by-using-httpwebrequest.aspx

呼び出すと以下の応答(ヘッダとコンテンツ)が返ってきます。応答ヘッダに Content-Length: 362 が含まれているのが分かりますか?

HTTP/1.1 200 OK Cache-Control: private Content-Type: application/json; charset=utf-8 Server: Microsoft-IIS/10.0 Set-Cookie: .ASPXANONYMOUS=-I_60O4A1AEkAAAAYjAxOTUwNzctOWM2Ny00YTM2LWFiYTQtZWY3OTBlZWUwMDlml656k9EBy823lc8QQ-Hmweaa_381; expires=Sun, 10-Jun-2018 19:11:20 GMT; path=/; HttpOnly X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Mon, 02 Apr 2018 08:31:20 GMT Content-Length: 362 {"GetCarsByDoorsResult":[{"Colour":"Red","Doors":5,"Make":"Audi","Model...

上に紹介した記事のコードに以下に一行を追加すると、

Console.WriteLine("Content-Length: {0}", endpointResponse.ContentLength);

結果は以下のようになって、期待通り HttpWebResponse.ContentLength プロパティで応答ヘッダの Content-Length: 362 の値を取得できます。

Content-Length: 362 Make: Audi, Model: A4, Doors: 5 Make: Ford, Model: Focus, Doors: 5 Make: Renault, Model: Laguna, Doors: 5 Make: Toyota, Model: Previa, Doors: 5

なので、質問者さんのケースで -1 になるというのは、サーバーからの応答ヘッダに Content-Length の設定がないということだと思います。Fiddler 等のキャプチャツールを使って応答ヘッダを調べてみてください。

Fiddler のお勧め
http://surferonwww.info/BlogEngine/post/2011/05/25/Recommendation-of-Fiddler.aspx

投稿2018/04/02 09:02

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dai49

2018/04/03 02:30

回答、試していただきありがとうございます。 参考ページをコピペして試そうとしたのですがSystem.Runtime.Serialization.Json;が追加できなかったのでそこから調べてみます。 気になったのがPOSTメソッドでHttpWebReqest.ContentLengthを設定しているのですが送付したデータのlengthが返ってきているのですか?
退会済みユーザー

退会済みユーザー

2018/04/03 04:49 編集

> 参考ページをコピペして試そうとしたのですが そんなことはする必要はないでしょう。 開発マシンに Fiddler をインストールして、今あなたがアクセスしているサイトにアクセスし、応答ヘッダの Content-length の有無を見て、HttpWebResponse.ContentLength プロパティの取得結果を見れば分かることだと思います。 > 気になったのがPOSTメソッドでHttpWebReqest.ContentLengthを設定しているのですが送付したデータのlengthが返ってきているのですか? 違います。 POST なので要求側にもコンテンツがあります。紹介した記事の場合それは {"doors":5} です。HttpWebReqest.ContentLength にはそのバイト数を設定してます。(正確に言うと、文字列 {"doors":5} を UTF-8 のバイト列に変換したときのバイト数) 一方、サーバから返ってくるのはサーバーが返すコンテンツの length です。それは上にも書きましたが {"GetCarsByDoorsResult":[{"Colour":"Red","Doors":5,"Make":"Audi","Model... です。(... は省略の意味) 基本的な知識をお持ちでないようにお見受けします。基本的なところを少し勉強しましょう。
dai49

2018/04/06 02:47

返信ありがとうございます。 Fiddlerインストールしてみました。 http://yahoo.co.jpで試してみたのですが、作ったコードだと-1にで表示されますがFiddlerで見るとヘッダーにContentLengthが設定されていて数値も表示されていました。 教えていただいたサイトへのgetだと作ったコードでもContentLengthヘッダーが取得できました。 ますます分からなくなってきてしまいました。 まだ勉強始めたばかりで理解できずすみません。 勉強します。 {"doors":5} という条件のリクエストデータを送り、responseでサーバー内の{"doors":5}に該当するデータが返ってくるというようなイメージでしょうか?
退会済みユーザー

退会済みユーザー

2018/04/06 04:29 編集

> http://yahoo.co.jpで試してみたのですが、作ったコードだと-1にで表示されますがFiddlerで見るとヘッダーにContentLengthが設定されていて数値も表示されていました。 自分でも試してみました。 http://yahoo.co.jp を要求すると HTTP 301 応答が返ってきて、https://www.yahoo.co.jp/ にリダイレクトされます。 その場合、HttpWebResponse.ContentLength プロパティで取得できるのは、https://www.yahoo.co.jp/ の応答ヘッダに含まれる Content-length の値、Content-Length がなければ -1 となるようです。 (最初の応答でなくリダイレクト先の応答の結果になるということが書いてある Microsoft の文書は見つけられませんでしたが、結果からそうなるのは確認しました) 確かに、http://yahoo.co.jp 要求に対する HTTP 301 応答に含まれるヘッダには Content-Length: 3189 が含まれます。 しかしながら、HttpWebRequest は直ちにリダイレクト先として指定されている https://www.yahoo.co.jp/ を要求します。 https://www.yahoo.co.jp/ の応答ヘッダは以下の通りで(説明に不要な部分は省略しています)、Chunked エンコーディングになっており Content-Length は含まれません。 HTTP/1.1 200 OK Date: Fri, 06 Apr 2018 03:44:07 GMT Expires: -1 Pragma: no-cache Cache-Control: private, no-cache, no-store, must-revalidate Content-Type: text/html; charset=UTF-8 Age: 0 Transfer-Encoding: chunked その結果、HttpWebReqest.ContentLength は MSDN ライブラリに書いてある通り -1 になるのだと思います。 > {"doors":5} という条件のリクエストデータを送り、responseでサーバー内の{"doors":5}に該当するデータが返ってくるというようなイメージでしょうか? そこは今回の話とは全く関係ないので、とりあえず忘れた方が良いと思うのですが、とりあえず説明すると・・・ 要求を受ける WCF サービスの GetCarsByDoors(int doors) メソッドが POST 要求を受け、コンテンツに {"doors":5} という JSON 文字列があると、5 という数字が引数の doors に渡されます。 そうすると、そのメソッド内でドアの数が 5 の車を検索し、その結果として得た List<T> 型オブジェクトを JSON 文字列として返すという仕組みになってます。
guest

0

質問者さんの質問に対してほぼ直接的な回答が得られていると思いますので補足程度ですが:

Content-Lengthは前の回答者さんらが答えられていたように、HTTPリクエストとレスポンスの内容によって入る場合もあれば入らない場合もあり、それを実際に送受信するプログラムがどう実装しているかで変わってきているのだと考えられます。

そんな場合、リファレンスとしてRFCを読んで「本来どうであるべき(≒正しい)なのか」を確認し、実際の動きを比べてみるとどこがおかしいのか見えてきたり、どうすべきかのヒントを得られることがあります。

例えば Content-Lengthはヘッダーフィールドに属するものですが、HTTP/1.1に関する最近(2014年6月)のRFC
RFC 7230 3.3.2. Content-Length
を見るとContent-Lengthをセットするケースとしないケースの様々な例が記述されています。

ここでRFCについて少し注意しなければならないのは、RFCと言うのはただの仕様の「提案書(Request For Comments)」であって、SHOULDとあれば「そうすべき」との提案で、MUSTであればそれを「しなければならない」とのように定義していることです。MUSTに関して実装ではそれに従っていないとHTTP/1.1に準拠したアプリケーションとは言えませんし、SHOULDであれば、必ずしも守らなければならないものでもないので、動きが少し違っていても仕方ありません。また、HTTP/1.1自体が長い時間を経ているので、サーバーやクライアントが古いRFCに準拠しているケースもあります。

パケットキャプチャーして見た時にContent-Lengthが無ければ、上記も参考にしてみてください。

投稿2018/04/03 03:13

編集2018/06/20 08:27
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dai49

2018/04/06 02:55

回答ありがとうございます。 参考にさせていただきます。
guest

0

レスポンスヘッダに
Transfer-Encoding: chunked
が指定されている場合、Content-Lengthは送信されてきません。
ですので、送信されてきたデータ長を知りたいだけであればStream等から得られるバイト数で問題ありません。

投稿2018/04/02 12:03

hmmm

総合スコア818

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dai49

2018/04/03 02:04

回答ありがとうございます。 streamから取る方法も検討してみます。
guest

0

どこかでContent-Lengthと実際のデータ数が違うことがある、と読んだことがあります。
まあ、しょせんはその程度のもの、と思っておけばいいかと。

投稿2018/04/02 12:13

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dai49

2018/04/03 01:17

回答ありがとうございます。 データ数が違うことがあるのは知らなかったです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問