25

Retrofit を使用して基本的な POST リクエストを実行し、リクエストに基本的な @Body を提供しています。

@POST("/rest/v1/auth/login")
LoginResponse login(@Body LoginRequest loginRequest);

Retrofit のインターフェイスを構築するときは、独自のカスタム OkHttpClient を提供しています。それに対して行っているのは、独自のカスタム認証を追加することだけです。

    @Provides
    @Singleton
    public Client providesClient() {
        OkHttpClient httpClient = new OkHttpClient();

        httpClient.setAuthenticator(new OkAuthenticator() {
            @Override
            public Credential authenticate(Proxy proxy, URL url, List<Challenge> challenges) throws IOException {
                return getCredential();
            }

            @Override
            public Credential authenticateProxy(Proxy proxy, URL url, List<Challenge> challenges) throws IOException {
                return getCredential();
            }
        });

        return new OkClient(httpClient);
    }

これは、OKHttp を使用して直接リクエストを送信したり、レトロフィットを使用して他の GET リクエストを送信したりする場合にうまく機能しますが、レトロフィットを使用して POST リクエストを実行すると、次のエラーが発生します。

Caused by: java.net.HttpRetryException: Cannot retry streamed HTTP body
            at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:324)
            at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:508)
            at com.squareup.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:136)
            at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:94)
            at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:49)
            at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:357)
            at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:282)
            at $Proxy3.login(Native Method)
            at com.audax.paths.job.LoginJob.onRunInBackground(LoginJob.java:41)
            at com.audax.library.job.AXJob.onRun(AXJob.java:25)
            at com.path.android.jobqueue.BaseJob.safeRun(BaseJob.java:108)
            at com.path.android.jobqueue.JobHolder.safeRun(JobHolder.java:60)
            at com.path.android.jobqueue.executor.JobConsumerExecutor$JobConsumer.run(JobConsumerExecutor.java:172)
            at java.lang.Thread.run(Thread.java:841)

私はそれで遊んだ。認証を削除し、認証を必要としないサーバーを指すと、正常に動作します。

  1. だから情報を発信しているに違いない。
  2. 認証チャレンジ リクエストを取得します。
  3. チャレンジリクエストにお応えします。
  4. リクエストを再送信しようとすると、エラーがスローされます。

これを回避する方法がわかりません。どんな助けでも素晴らしいでしょう。

4

5 に答える 5

14

最善の策は、OkHttp の代わりにRequestInterceptorOkAuthenticatorを介して Retrofit に資格情報を提供することです。そのインターフェースは、リクエストを再試行できる場合に最適に機能しますが、あなたのケースでは、それが必要であることがわかった時点で既に投稿本文を破棄しています。

ユーザー名とパスワードを必要な形式でエンコードできる OkAuthenticator の Credential クラスを引き続き使用できます。必要なヘッダー名はAuthorization.

于 2014-01-26T23:46:44.933 に答える
6

基本的な承認の場合、次のようなヘッダーを提供できます。

@GET("/user")
void getUser(@Header("Authorization") String authorization, Callback<User> callback)
于 2014-09-23T22:45:38.610 に答える
1

最新バージョンの Retrofit / OkHttp でこれを行っている場合、現在の一連のソリューションでは不十分です。Retrofit は RequestInterceptor を提供しなくなったため、同様のタスクを実行するには OkHttp のインターセプターを使用する必要があります。

インターセプターを作成します。

public class HttpAuthInterceptor implements Interceptor {
  private String httpUsername;
  private String httpPassword;

  public HttpAuthInterceptor(String httpUsername, String httpPassword) {
    this.httpUsername = httpUsername;
    this.httpPassword = httpPassword;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    Request newRequest = chain.request().newBuilder()
        .addHeader("Authorization", getAuthorizationValue())
        .build();

    return chain.proceed(newRequest);
  }

  private String getAuthorizationValue() {
    final String userAndPassword = "httpUsername" + ":" + httpPassword;
    return "Basic " + Base64.encodeToString(userAndPassword.getBytes(), Base64.NO_WRAP);
  }
}

インターセプターを OkHttp クライアントに追加する必要があります。

// Create your client
OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new HttpAuthInterceptor("httpUsername", "httpPassword"))
    .build();

// Build Retrofit with your client
Retrofit retrofit = new Retrofit.Builder()
    .client(client)
    .build();

// Create and use your service that now authenticates each request.
YourRetrofitService service = retrofit.create(YourRetrofitService.class);

上記のコードはテストしていないため、多少の変更が必要になる場合があります。私は現在、Android用のKotlinでプログラミングしています。

于 2016-12-12T16:04:51.000 に答える