最近、AtomPubのクライアントの実装をC#でちまちま書いてるんだが、こいつをテストしてて、Hatena Blogだとなんとも無いのに、Livedoor Blogだと、417 Expectation Failedの例外を投げられて、頭抱え込んだのでメモ。
なんてことは無い、答えは、
アフェリエイトで主夫がマネタイズ始めましたのlivedoor blogで417 Expectation Failed
初学者の箸置のWebRequestのExpectにデフォルトで100-continueがつく件
マジックナンバーのHttpClientの417 Expectation Failed
MSDNのServicePoint.Expect100Continueプロパティ
この動きって知らなかった。
HTTPリクエストでは、POSTの場合、ヘッダーとボディの両方をいきなり送りつけるのではなくて、
- クライアントは、ヘッダーだけ送る。この際、Expect: 100-continueをヘッダーに足しておく。
- サーバーは、OKなら100系、ダメなら4XX系を返す。
- クライアントは、100の場合は、ボディを送信する。
とすることで、いきなりボディの大量データを送る前に、拒否されるのかどうかを検証でき、無駄な通信量を減らすことができる。
例えば、クライアントが認証付きでリクエストする際、いきなりヘッダーとボディを送るのではなく、まず認証の情報とExpect: 100-continueが入ったヘッダーを投げて、100 (Continue)が来たらボディを送る、401 (Unauthorized)ならボディを送らない。とすればよい。
で、で、
.NET FrameworkのHttpWebRequestクラスはPOSTに関してデフォルトでこの機能がONになっている。
が、この機能を受け付けないサーバーが世の中には存在する。この機能を受け付けないサーバーは、一般的には、417 Expectation Failedが返ってくる。中にはだんまり決め込むサーバーもあるらしい。
ぐぐってみると、LivedoorBlogのAtomPubだったり、TwitterAPIだったりが417を返すとか。。。
んじゃ、HttpWebRequestのこの機能をOFFにしなくちゃならないのだが、
httpWebRequest.Expect = null; // or = “”; or = “ “;
とか、ましてや、
httpWebRequest.Headers[“Expect”] = null;
では消えてくれない。
正解は、
httpWebRequest.ServicePoint.Expect100Continue = false;
ということで。。。
System.Net.Http.HttpClientを使っている場合は、System.Net.Http.HttpRequestMessageのHeaders.ExpectContinueプロパティをfalseにするか、httpClient.DefaultRequestHeaders.ExpectContinue = falseとする。
いろいろ知らんかった。