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

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

ただいまの
回答率

89.53%

C#でリクエストヘッダーとボディを一緒に送信する

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,636

YutaNkai

score -68

実現したいことは以下のサイトのブロードキャストメッセージを送るの部分です。
Messaging APIリファレンス

他サイトを参考に以下のようなコードを作成しました。

            // To creat HttpClient
            var client = new HttpClient();

            // Accesstoken
            var accessToken = "token";

            // URL
            var url = "https://api.line.me/v2/bot/message/multicast";

            // Message
            var json = "{ \"type\" : text, \"text\" : \"Hello World\"  }";
            // var content = new StringContent("{ \"your\": \"content\", \"maybe\": \"json\" }");
            // content.Headers.Add("X-SOME-RANDOM", "header-value");

            var request = new HttpRequestMessage(HttpMethod.Get, url);
            // Request Header
            request.Headers.Add("ContentType", "application/json");
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            // Request Body
            request.Headers.Add("to", "userId");
            request.Headers.Add("messages", json);
            var response = await client.SendAsync(request);

これを実行するとインターナルサーバーエラーになります。
リクエストヘッダーを設定する箇所は以下のサイトを参考にしました。
HttpClient でリクエストヘッダを設定する

リクエストヘッダーをそのまま、リクエストボディに適用した形です。
これだとよろしくないのでしょうか。

追記⓵
リクエストヘッダーとボディを分けるところは完成しましたが、どのようにして
ヘッダーにAuthorizationを設定すればよいでしょうか。現在のコードは以下です。

            var json = @"{""type"":""text"", ""text"":Hello World}";
            var content = new StringContent(json, Encoding.UTF8, @"application/json");

            using (var client = new HttpClient())
            {
                var response = await client.PostAsync($"http://foo.example.com", content);
            }

追記⓶
現在のコードは以下です。ボディとヘッダーを同時に設定できました。

            // To creat HttpClient
            var client = new HttpClient();

            // Accesstoken
            var accessToken = "token";

            // URL
            var url = "https://api.line.me/v2/bot/message/broadcast";


            var request = new HttpRequestMessage(HttpMethod.Post, url);
            // Request Header
            request.Headers.Add("Authorization", "Bearer " + accessToken);
            var parameters = new Dictionary<string, string>()
            {
                { "messages", "Hello World" },
            };

            request.Content = new StringContent(
                parameters.ToString(),
                Encoding.UTF8,
                "application/json"
            );

            await client.SendAsync(request);//ここでデバックで停止

デバック結果
イメージ説明

値も指定通りになっている気がします。
特にサーバーエラー等は出ていません。

追記⓷
現在、ローカルホストを外部に公開するためにngrokを使用しています。そこでは200Okのレスポンスが返ってきます。
が、fiddlerではエラーになっているようです。
以下がその画面と、現在のコードです。
イメージ説明

            // To creat HttpClient
            var client = new HttpClient();

            // Accesstoken
            var accessToken = "token=";

            // URL
            var url = "https://api.line.me/v2/bot/message/broadcast";

            // POST
            var request = new HttpRequestMessage(HttpMethod.Post, url);

            // Request Header
            request.Headers.Add("Authorization", "Bearer " + accessToken);

            var str1 = new Dictionary<string, string>();
            str1.Add("type", "text");
            str1.Add("text", "test test test");

            var str2 = new Dictionary<string, Dictionary<string, string>>();
            str2.Add("messages", str1);

            var json = JsonConvert.SerializeObject(str2);

            request.Content = new StringContent(
                json.ToString(),
                Encoding.UTF8,
                "application/json"
            );

            await client.SendAsync(request);

追記④
現在POSTでブロードキャストメッセージを送ると以下のようにFiddlerに表示されます。

POST https://api.line.me/v2/bot/message/broadcast HTTP/1.1
Authorization: Bearer my token
Content-Type: application/json; charset=utf-8
Host: api.line.me
Content-Length: 52
Expect: 100-continue
Connection: Keep-Alive

{"messages":{"type":"text","text":"test test test"}}

レスポンスは400(Bad request)になっています。
見た感じだと、APIリファレンスの要求に沿っている気がするのですが、どこかおかしいい箇所がありますでしょうか。

ちなにみに以下が現在成功している、マルチメッセージのFiddlerの結果です。比べても大きな違いはない気がします。
また、マルチメッセージはテンプレートの既存メソッドを指定しています。

POST https://api.line.me/v2/bot/message/multicast HTTP/1.1
Authorization: Bearer my token
Content-Type: application/json; charset=utf-8
Host: api.line.me
Content-Length: 143
Expect: 100-continue
Connection: Keep-Alive

{"to":["ID1","ID2"],"messages":[{"type":"text","text":"マルチメッセージ"}]}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

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

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

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

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

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

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/10/28 11:09

    またアクセストークン出しっぱなしですけど、前に複数のユーザーから重々指摘を喰らったはずです。忘れていいことではないですよ。さいあく、乗っ取られても悪用されてもそれにより社会的に制裁食らってもいいってことですかね。

    キャンセル

  • m.ts10806

    2019/10/28 11:14

    これも何度も注意してますが、編集したところで編集履歴から確認できるんですよ。ウッカリで済まされることじゃないって認識持ってください。被害を被るのはあなただけでは済まないのです。
    その程度の意識しかないならプログラミングから手を引いてください。

    キャンセル

  • m.ts10806

    2019/10/28 11:18

    回答がつくと削除依頼が直接できないからすぐに非表示にもならない。運営確認が必要だから問い合わせが必要になり時間もかかる。
    慎重に慎重を重ねないといけない場面で「あとで編集すればいっか」程度の認識しかないのは致命的です。
    最近それで活動自粛した有名な芸人さんがいますが、同じことです。
    ルーズな人にはプログラミングは全く不向きどころか周囲に大損害を与えるだけだ

    キャンセル

回答 3

+4

リクエストヘッダーをそのまま、リクエストボディに適用した形です。
これだとよろしくないのでしょうか。

はい、このままだと、To: userIdのようなHTTPヘッダを指定する意味になってしまいます。

リクエストボディは、HttpRequestMessage.Contentプロパティから指定してください(MSDN)。

あと、当該APIはPOSTなのに、HttpMethod.GetGETリクエストを作成しているようです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/28 10:46

    > ネットでボディを調べると、(中略)のような感じで指定しているのですが

    えっと、「HTTPContent+PostAsync」と「HttpRequestMessage+SendAsync」と、どちらの方法でやりたいのですか?使う関数が違えばやりかたも違ってきます。「ネットで調べたから」といって簡単に方法を変えてしまうと、何もかも書き直しになってしまいます。

    キャンセル

  • 2019/10/28 10:55

    申し訳ございません。さらなる調査により、コードを変更し、デバックも行ったので、状況を追記します。

    キャンセル

  • 2019/10/28 11:09

    HttpRequestMessage+SendAsyncで実現したいなと現段階では考えております。

    キャンセル

+2

ユーザー認証用のトークンが取得できているのか疑問ですが、そこは本題とは関係ないようなのでとりあえず置いといて・・・

追記⓶
現在のコードは以下です。ボディとヘッダーを同時に設定できました。

そのコードでとりあえず送信はできているようですが、リクエストボディが API の要求に合ってないように思えます。(トークンの話は上に書いたようにちょっと置いといて)

参考にされている「Messaging APIリファレンス」を見ると、リクエストボディとして messages プロパティにメッセージオブジェクトの配列を設定して JSON 文字列で送信するということのようです。

そのリクエストボディが StringContent の第一引数の parameters.ToString() ということになりますが、実際どうなっているかデバッガを使うなどして調べてみてください。

あと、API とのやり取りを見るには Fiddler を使うのがお勧めです。以下の画像はベアラトークンを要求する API に JSON 文字列を POST 送信したときの要求・応答をキャプチャした結果です。

イメージ説明

トークンを含めたヘッダ情報が正しく設定され、リクエストボディとして JSON 文字列が期待通り設定されているかどうかが確認できます。また、応答も HTTP 200 と正常であることも確認できます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/28 14:17

    回答ありがとうございます。

    確認⓵
    '{
    "messages":[
    {
    "type":"text",
    "text":"Hello, world1"
    },
    {
    "type":"text",
    "text":"Hello, world2"
    }
    ]
    }'

    をJSON文字列で記述して、送信ということでしょうか。

    確認⓶
    また、Content-typeの設定は
    request.Headers.Add("Authorization", "Bearer " + accessToken);
    のようにAdd()で行うべき(String Contentでは行わない)でしょうか???

    キャンセル

  • 2019/10/28 14:30

    > 確認⓵

    それを聞くならマルチポスト https://teratail.com/questions/219750 を何とかしてください。

    > 確認⓶

    今のコードで上の回答の Fiddler 画像の Content-type の通りとなるはずです。そういうことを確認するために Fiddler を使うことをお勧めしているのですから、聞く前にやってみましょう。

    キャンセル

  • 2019/10/28 16:01

    ありがとうございます。ダウンロードしました。
    が、そもそも送信するJSON文字列が間違っていおりました。
    現在はそこで落ちてしまいます。

    キャンセル

  • 2019/10/28 18:33 編集

    マルチポストよりアクセストークンの問題を。(何度目だろうこれ)
    →あぁそういうこと・・・運営依頼したか何かなら返事してほしいですね。無視されてる気しかしない。

    キャンセル

check解決した方法

-10

お疲れ様です。お騒がせしました。
解決いたしました。

流れとしては以下のようになりました。

POSTしたいJSON値をオブジェクト化する→シリアライズ→ToStirngで文字列

オブジェクト化に関しては、以下のサイトを参考にしました。
http://json2csharp.com/

ヘッダーとボディの設定に関しては、質問本文にあるリンク先と以下のサイトを参考にしました。
https://codeday.me/jp/qa/20190601/916764.html

SurferOnWww様に教えていただいたFiddlerも非常に助けとなりました。
ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 89.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる