結論だけ知りたい人は
この記事のタイトルが結論になっていますので、それを読んで下さい。
また、ソースコードは、この記事の最後の方に載っています。
Github API の /markdown/raw では Content-type ヘッダが必要
http://hacknote.jp/archives/12087/ によると、Content-typeヘッダが必要らしい。なるほどやってみる。
mint@ubuntu:~$ wget --post-data='# Hello\nWorld!' https://api.github.com/markdown/raw --2017-09-03 00:06:42-- https://api.github.com/markdown/raw api.github.com (api.github.com) をDNSに問いあわせています... 192.30.255.116, 192.30.255.117 api.github.com (api.github.com)|192.30.255.116|:443 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 415 Unsupported Media Type 2017-09-03 00:06:43 エラー 415: Unsupported Media Type。 mint@ubuntu:~$ wget --post-data='# Hello\nWorld!' --header='Content-type:text/plain' https://api.github.com/markdown/raw --2017-09-03 00:16:07-- https://api.github.com/markdown/raw api.github.com (api.github.com) をDNSに問いあわせています... 192.30.255.117, 192.30.255.116 api.github.com (api.github.com)|192.30.255.117|:443 に接続しています... 接続しました。 HTTP による接続要求を送信しました、応答を待っています... 200 OK 長さ: 176 [text/html] `raw.5' に保存中 raw.5 100%[==================================>] 176 --.-KB/s in 0s 2017-09-03 00:16:08 (24.2 MB/s) - `raw.5' へ保存完了 [176/176] mint@ubuntu:~$ cat raw.5 <h1> <a id="user-content-hellonworld" class="anchor" href="#hellonworld" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Hello\nWorld!</h1>
しかしそこじゃない
wgetは出来たので、C#からもリクエストを叩いてみようとするが・・・
Content-typeを入れてもダメで、出てきたエラーメッセージを見ても原因不明。
System.Net.WebException: サーバーによってプロトコル違反が発生しました. Section=ResponseStatusLine 場所 System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request) 場所 System.Net.WebClient.UploadData(Uri address, String method, Byte[] data) 場所 System.Net.WebClient.UploadData(String address, String method, Byte[] data) 場所 MarkDownToXml.Program.Main(String[] args) 場所 C:\********\Program.cs:行 21 続行するには何かキーを押してください . . .
仕方がないので、requestb.in にPOST投げてリクエストを比較する。上がオプション無しのwget、下がWebClientです。
( wget のデフォルトは application/x-www-form-urlencoded になる、なるほど。)
User-Agent で弾かれるとは思えないし Accept が無いのが原因かな・・・? と思ったら User-Agentでした。Content-type と User-Agent の両方が必要らしいです。以下ソースコード。
using System; using System.Text; using System.Net; class Program { static void Main(string[] args) { const string url = "https://api.github.com/markdown/raw"; try { WebClient wc = new WebClient(); wc.Headers["Content-Type"] = "text/plain"; wc.Headers["User-agent"] = "nyaaaaaaaaaaaaaaaaaaaaaan"; byte[] resData = wc.UploadData(url, "POST", Encoding.UTF8.GetBytes("# Hello\nWorld!")); wc.Dispose(); Console.WriteLine(Encoding.UTF8.GetString(resData)); } catch (Exception e) { Console.WriteLine(e.ToString()); } } }
出力はこんな感じ。
<h1> <a id="user-content-hello" class="anchor" href="#hello" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Hello</h1> <p>World!</p>
もしHttpClientを使う場合は
こんな感じになるっぽいです。長いのでasyncを使わないならWebClientの方が良さそう。
using System; using System.Text; using System.Net.Http; class Program { static void Main(string[] args) { string url = "https://api.github.com/markdown/raw"; try { var client = new HttpClient(); client.DefaultRequestHeaders.UserAgent.ParseAdd("nyaaaaaaaaaaaaaaaaaaaaaan"); var stringContent = new StringContent("# Hello\nWorld!", Encoding.UTF8, "text/plain"); var task = client.PostAsync(new Uri(url), stringContent); task.Wait(); var result = task.Result; if (result.IsSuccessStatusCode) { var task2 = result.Content.ReadAsStringAsync(); task2.Wait(); Console.WriteLine(task2.Result); } else { Console.WriteLine("StatusCode : " + result.StatusCode); Console.WriteLine("ReasonPhrase : " + result.ReasonPhrase); } } catch (Exception e) { Console.WriteLine(e.ToString()); } } }
User-agentが無いと、こんなエラーが出ます。
System.AggregateException: 1 つ以上のエラーが発生しました。 ---> System.Net.Http.HttpRequestException: この要求の送信中 にエラーが発生しました。 ---> System.Net.WebException: サーバーによってプロトコル違反が発生しました. Section=ResponseStatusLine 場所 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) 場所 System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) --- 内部例外スタック トレースの終わり --- --- 内部例外スタック トレースの終わり --- 場所 System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) 場所 System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) 場所 System.Threading.Tasks.Task.Wait() 場所 Program.Main(String[] args) 場所 C:\********\Program.cs:行 19 ---> (内部例外 #0) System.Net.Http.HttpRequestException: この要求の送信中にエラーが発生しました。 ---> System.Net.WebException: サーバーによってプロトコル違反が発生しました. Section=ResponseStatusLine 場所 System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult, TransportContext& context) 場所 System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar) --- 内部例外スタック トレースの終わり ---<---