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

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

ただいまの
回答率

89.12%

javaのHttpURLConnectionで401が返ってくる

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 3,609

Begi

score 53

お世話になります。
現在HttpURLConnectionでとあるAPIにリクエストを送り、image/jpegのバイナリデータをレスポンスとして取得しています。
レスポンスコード200で正常に取得できているのですが、体感30分経過するとそのリクエストのレスポンスコードが401 Unautholizedになってしまいます。
リクエストの流れとして、CookieManagerを使用したコネクションの確立を最初に行ってからリクエストを行っています。

以下コードになります。

public HttpURLConnection getConnection() throws Exception {
        HttpURLConnection con = null;
        try {
            CookieManager manager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
            CookieHandler.setDefault(manager);
            URL url = new URL("APIのURL");
            con = (HttpURLConnection) url.openConnection();
            con.setDoOutput(true);
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type", "application/json");
            con.setRequestProperty("Accept", "application/json");
            String requestBody = String.format("{\"mail_address\": \"%s\", \"password\": \"%s\"}", "admin", "pass");
            OutputStream os = con.getOutputStream();
            os.write(requestBody.getBytes(Charset.forName("UTF-8")));
            if (con.getResponseCode() == 200) {
                StringBuilder responseBody = new StringBuilder();
                InputStream is = con.getInputStream();
                InputStreamReader isReader = new InputStreamReader(is, "UTF-8");
                BufferedReader bufReader = new BufferedReader(isReader);
                String line = null;
                while((line = bufReader.readLine()) != null) {
                    responseBody.append(line);
                }
                bufReader.close();
                isReader.close();
                is.close();

                System.out.println("レスポンスボディ: " + responseBody.toString());
            }
        } catch (Exception e) {
                System.out.println("エラー");
            con = null;
        }
        return con;
    }


上記で取得したコネクションを使用し、下記コードによりリクエストを行っています。

public InputStream getImageEntity(HttpURLConnection con) throws Exception {
        InputStream is = null;
        // URLの作成
        URL url = new URL("APIのURL");
        con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod("GET");
        con.setDoOutput(true);
        con.setInstanceFollowRedirects(false);
        con.setRequestProperty("Accept", "image/jpeg");
        con.connect();
        int resCode = con.getResponseCode();
        if (resCode == HttpURLConnection.HTTP_OK) {
            is = con.getInputStream();
        }
        return is;
    }


捕捉として、上記InputStreamの戻り値がnullだった場合にはNO_IMAGEの画像をブラウザに返すようにしています。
なお、CookieHandler.getDefault()が存在する場合はコネクションの取得は省略しています。

if (CookieHandler.getDefault() == null) {
    con = getConnection();
}

リクエスト先のサーバはこちらからは閲覧できないのですが、私が知識不足なのもありこちらのコードが間違っているのかと思っています。
どこか改善点がありましたらご指摘いただけませんでしょうか。
よろしくお願いします。


  • 捕捉情報
    APIのURLはhttpsでした。
    また、ブラウザからnew URLの引数であるURLを叩くと、画像が表示されます。
    ※前回リクエスト時から30分経過するとログイン画面に飛ばされます(API提供元サイトのセッション有効時間が30分だと思われるため)。
    以上、何かヒントになればと思い掲載させていただきました。
    よろしくお願いします。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • Mr_Roboto

    2016/07/28 23:19

    レスポンスコード200が返って来てから30分開けてリクエストしているのですか?それともその間ずっとリクエストを繰り返しているのですか? 後者であれば相手先からリクエストが多すぎるため拒否されているという可能性は無いですか?

    キャンセル

  • Begi

    2016/07/29 00:00

    BJCRobotさん
    コメントありがとうございます。
    30分開けてリクエストすると401が返ってきてしまいます。逆にCookieHandler.getRequest()の判定をせずにgetConnectionメソッドを連続して実行しても401が時々返ってきました。

    キャンセル

回答 1

checkベストアンサー

+1

手がかりとしてCookieManager にストアされているCookieの情報を出力し、「200の時」と「401の時」を見比べてみてはどうでしょう。

■それ以外で気になった点

  • getImageEntityのメソッドでsetDoOutputをtrueにしているのはなぜでしょう。
  • getConnectionでcon.connectを読んでいない理由は何でしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/29 10:28

    yonaさん
    大変お恥ずかしい話ですが、Cookieの有効期限の確認方法がよくわかりません。
    getImageEntityメソッド内で通信終了後にCookieStoreやCookieManagerを使用し確認するのでしょうか。
    また、有効期限を確認し30分等だった場合に、Cookieが存在しなければ再度getConnectionメソッドを呼びたいのですが、どのように判定したらいいでしょうか。現在CookieHandler.getDefault()で確認していますがこれはCookieHandlerがデフォルト値をセットしているかどうかという話でCookieの有無とは関係ないという認識で間違いないでしょうか。

    矢継ぎ早に質問してしまい申し訳ありません。

    キャンセル

  • 2016/07/29 11:10

    もしかしたら、HttpCookie#toStringで表示されるかもしれないです。またはHttpCookie#hasExpiredで有効期限切れを確認できます。

    ただ、401が帰ってきたら権限切れなので再度getConnectionを行い、getImageEntityを行う実装にすればいいと思いますよ。

    キャンセル

  • 2016/07/29 11:38

    yonaさん
    hasExpiredで確認できました。ありがとうございます。
    また、401だったら(上記getImageEntityメソッドだとInputStreamがnullだったら)getConnectionからやり直す方法で問題なさそうです。
    ありがとうございました、助かりました。

    キャンセル

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

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