Android Retrofit Parameterized @Headers


85

Tôi đang sử dụng OAuth và tôi cần đặt mã thông báo OAuth trong tiêu đề của mình mỗi khi tôi đưa ra yêu cầu. Tôi thấy @Headerchú thích, nhưng có cách nào để làm cho nó được tham số hóa để tôi có thể truy cập vào lúc chạy không?

Đây là khái niệm

@Header({Authorization:'OAuth {var}', api_version={var} })

Bạn có thể vượt qua chúng trong Runtime?

@GET("/users")
void getUsers(
    @Header("Authorization") String auth, 
    @Header("X-Api-Version") String version, 
    Callback<User> callback
)

Bạn đã bao giờ con số này ra? Tôi cần phải vượt qua trong một mã thông báo trong tiêu đề cũng
theSociableme

Tôi cũng đang tìm giải pháp cho vấn đề này, từ tài liệu có vẻ như chú thích @Headers () trên phương thức thêm từng trường vào tiêu đề một, nhưng chỉ hỗ trợ các ký tự. Và @Header ("tham số") Chú thích tham số chuỗi chuỗi thay thế tiêu đề bằng giá trị được cung cấp.
nana

2
Ở đây cũng vậy, không thể tìm hiểu cách xử lý các phiên khi sử dụng trang bị thêm.
FRR

Chúng tôi không cần phải vượt qua tất cả các mục, trang bị thêm tự xử lý tất cả. Vui lòng kiểm tra liên kết câu trả lời của tôi trong StackOverflow.
Subin Babu

Câu trả lời:


98

Bên cạnh việc sử dụng tham số @Header, tôi muốn sử dụng RequestInterceptor để cập nhật tất cả yêu cầu của bạn mà không thay đổi giao diện của bạn. Sử dụng một cái gì đó như:

RestAdapter.Builder builder = new RestAdapter.Builder()
    .setRequestInterceptor(new RequestInterceptor() {
        @Override
        public void intercept(RequestFacade request) {
            request.addHeader("Accept", "application/json;versions=1");
            if (isUserLoggedIn()) {
                request.addHeader("Authorization", getToken());
            }                    
        }
    });

p / s: Nếu bạn đang dùng Retrofit2 thì nên dùng Interceptorthay vìRequestInterceptor

RequestInterceptorkhông còn có sẵn trong Retrofit 2.0


3
Điều này không liên quan trực tiếp nhưng nếu bạn thấy mình cần lấy các giá trị từ đối tượng yêu cầu để tạo tiêu đề Ủy quyền, bạn sẽ cần phải mở rộng ApacheClient và trong khi thực thi, sao chép đối tượng Yêu cầu (List <Header> headers = ... ; Yêu cầu requestNew = new Request (request.getMethod (), request.getUrl (), headers, request.getBody ()); request = requestNew).

1
Đó là một thủ thuật mà messes một mã lên, tốt hơn sử dụng @ câu trả lời của Nana
Ivan Fazaniuk

1
RestAdapterphụ thuộc vào Retrofit1, trong Retrofit2 thì như vậy Retrofit. Tôi sẽ sử dụng Retrofit2, vì vậy nó không có vấn đề gì nếu sử dụng RequestInterceptornhư mã trên?
Huy Tower

55

Có, bạn có thể vượt qua chúng trong thời gian chạy. Trên thực tế, hoàn toàn chính xác như bạn đã gõ nó ra. Điều này sẽ nằm trong lớp giao diện API của bạn, có tên là SecretApiInterface.java

public interface SecretApiInterface {

    @GET("/secret_things")
    SecretThing.List getSecretThings(@Header("Authorization") String token)

}

Sau đó, bạn chuyển các tham số cho giao diện này từ yêu cầu của bạn, một cái gì đó dọc theo những dòng đó: (ví dụ: tệp này sẽ là SecretThingRequest.java )

public class SecretThingRequest extends RetrofitSpiceRequest<SecretThing.List, SecretApiInteface>{

    private String token;

    public SecretThingRequest(String token) {
        super(SecretThing.List.class, SecretApiInterface.class);
        this.token = token;
    }

    @Override
    public SecretThing.List loadDataFromNetwork() {
        SecretApiInterface service = getService();
        return service.getSecretThings(Somehow.Magically.getToken());
    }
}

Đâu Somehow.Magically.getToken()là một lệnh gọi phương thức trả về mã thông báo, tùy thuộc vào bạn ở đâu và cách bạn xác định nó.

Tất nhiên, bạn có thể có nhiều hơn một @Header("Blah") String blahchú thích trong việc triển khai giao diện, như trong trường hợp của bạn!

Tôi cũng thấy nó khó hiểu, tài liệu nói rõ ràng là nó thay thế tiêu đề, nhưng KHÔNG !
Trên thực tế, nó được thêm vào như với @Headers("hardcoded_string_of_liited_use")chú thích

Hi vọng điêu nay co ich ;)


1
Tôi tìm thấy trong tài liệu rằng nó không thay thế tiêu đề hiện có: "Lưu ý rằng các tiêu đề không ghi đè lên nhau." Kiểm tra square.github.io/retrofit và "Header Thao tác"
Amio.io

37

Câu trả lời được chấp nhận là dành cho phiên bản cũ hơn của Retrofit. Đối với những người xem trong tương lai, cách thực hiện điều này với Retrofit2.0 là sử dụng ứng dụng khách OkHttp tùy chỉnh:

OkHttpClient httpClient = new OkHttpClient.Builder()
  .addInterceptor(new Interceptor() {
    @Override
    public Response intercept(Chain chain) throws IOException {
      Builder ongoing = chain.request().newBuilder();
      ongoing.addHeader("Accept", "application/json;versions=1");
      if (isUserLoggedIn()) {
        ongoing.addHeader("Authorization", getToken());
      }
      return chain.proceed(ongoing.build());
    }
  })
  .build();

Retrofit retrofit = new Retrofit.Builder()
  // ... extra config
  .client(httpClient)
  .build();

Hy vọng nó sẽ giúp một ai đó. :)


5
Trong cách sử dụng phổ biến với dagger2, retrofit2 sẽ là singleton, do đó httpclient sẽ không được tạo mỗi lần. trong trường hợp đó isUserLoggedIn () không có ý nghĩa, đúng không? Giải pháp duy nhất mà tôi có thể thấy hiện tại là buộc khởi động lại retrofit2 khi trạng thái đăng nhập của người dùng bị thay đổi, để tiêu đề thích hợp được thêm vào hoặc xóa khỏi yêu cầu .. hoặc có giải pháp rõ ràng nào đó mà tôi không thể thấy hiện tại? Cảm ơn.
bajicdusko

2
@bajicdusko đây là câu hỏi hóc búa giống hệt tôi. Bạn đã tìm ra giải pháp chưa? Có vẻ như thật lãng phí, và kỳ lạ là phiên bản trước lại hiệu quả hơn.
deed02392

@ deed02392 Bạn có thể đặt kết hợp Interceptormà bạn có thể đặt hoặc đặt lại bộ đánh chặn ở giai đoạn sau. Tuy nhiên, tôi sẽ tranh luận rằng việc trang bị thêm dưới dạng singleton có thể là một dấu hiệu của việc tối ưu hóa sớm. Không có chi phí nào khi tạo phiên bản trang bị thêm mới: github.com/square/retrofit/blob/master/retrofit/src/main/java/…
pablisco Ngày

Tôi đã không thực sự nghĩ về nó sâu sắc. Tôi có một số lớp ApiFactory cũng được khởi tạo bằng dagger2 và nó chịu trách nhiệm khởi tạo trang bị thêm. Tôi đã tiết lộ một phương thức công khai trong ApiFactory buộc khởi động lại phiên bản trang bị thêm khi cần, vì vậy nó khá đơn giản. Tôi có thể làm sai, nhưng nó đã hoạt động tốt và tôi đang sử dụng nó chỉ cho tiêu đề Ủy quyền nên nó được sử dụng khi người dùng đăng nhập hoặc đăng xuất. Một tùy chọn khác là sử dụng chú thích @Header bên trong định nghĩa điểm cuối, điều này không được chấp nhận đối với tôi. Tôi nên đặt nó trên mỗi điểm cuối mà không thực tế.
bajicdusko

@pablisco Ah theo tôi hiểu thì bạn không thể thêm hoặc xóa Interceptors sau khi tạo phiên bản Retrofit2.
chứng thư02392

7

Trang bị thêm 2.3.0

OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    okHttpClientBuilder
            .addInterceptor(new Interceptor() {
                @Override
                public okhttp3.Response intercept(Chain chain) throws IOException {
                    Request request = chain.request();
                    Request.Builder newRequest = request.newBuilder().header("Authorization", accessToken);
                    return chain.proceed(newRequest.build());
                }
            });

    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(GithubService.BASE_URL)
            .client(okHttpClientBuilder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build();

Tôi đang sử dụng cái này để kết nối với GitHub.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.