Android Retrofit Parameterized @Headers


85

ฉันใช้ OAuth และต้องใส่โทเค็น OAuth ในส่วนหัวทุกครั้งที่ส่งคำขอ ฉันเห็น@Headerคำอธิบายประกอบ แต่มีวิธีทำให้เป็นพารามิเตอร์เพื่อให้ฉันส่งผ่านไปได้หรือไม่

นี่คือแนวคิด

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

คุณสามารถส่งผ่าน Runtime ได้หรือไม่?

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

คุณเคยคิดออกไหม? ฉันต้องส่งโทเค็นในส่วนหัวด้วย
theSociableme

ฉันกำลังมองหาวิธีแก้ปัญหานี้เช่นกันจากเอกสารดูเหมือนคำอธิบายประกอบ@Headers ()ในวิธีการนี้จะเพิ่มฟิลด์ไปยังส่วนหัวทีละรายการ แต่รองรับเฉพาะตัวอักษรเท่านั้น และ@Header ("พารามิเตอร์")คำอธิบายประกอบพารามิเตอร์สตริงสตริงจะแทนที่ส่วนหัวด้วยค่าที่ให้มา
นานา

2
เหมือนกันที่นี่ไม่พบวิธีจัดการเซสชันเมื่อใช้ชุดติดตั้งเพิ่มเติม
FRR

เราไม่จำเป็นต้องส่งผ่านทุกรายการ แต่การติดตั้งเพิ่มเองก็จัดการได้ทั้งหมด โปรดตรวจสอบลิงก์คำตอบของฉันใน StackOverflow
Subin Babu

คำตอบ:


98

นอกจากใช้พารามิเตอร์ @Header แล้วฉันควรใช้ RequestInterceptor เพื่ออัปเดตคำขอทั้งหมดของคุณโดยไม่ต้องเปลี่ยนอินเทอร์เฟซของคุณ ใช้สิ่งที่ชอบ:

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: หากคุณใช้ Retrofit2 คุณควรใช้Interceptorแทนไฟล์RequestInterceptor

เนื่องจากRequestInterceptorไม่มีใน Retrofit 2.0 อีกต่อไป


3
สิ่งนี้ไม่เกี่ยวข้องโดยตรง แต่ถ้าคุณพบว่าตัวเองต้องการรับค่าจากออบเจ็กต์คำขอเพื่อสร้างส่วนหัวการอนุญาตของคุณคุณจะต้องขยาย ApacheClient และในการดำเนินการที่ซ้ำกันของวัตถุที่ร้องขอ (รายการ <ส่วนหัว> ส่วนหัว = ... ; ขอ requestNew = คำขอใหม่ (request.getMethod (), request.getUrl (), headers, request.getBody ()); request = requestNew)

1
นั่นเป็นเคล็ดลับที่ทำให้โค้ดยุ่งขึ้นใช้คำตอบของ @ nana ได้ดีขึ้น
Ivan Fazaniuk

1
RestAdapterขึ้นอยู่กับ Retrofit1 ใน Retrofit2 Retrofitมันเป็น ฉันจะใช้ Retrofit2 ดังนั้นจึงไม่มีปัญหาหากใช้RequestInterceptorตามโค้ดด้านบน?
Huy Tower

55

ใช่คุณสามารถส่งผ่านได้ในรันไทม์ ตามความเป็นจริงแล้วก็เหมือนกับที่คุณพิมพ์ออกมา สิ่งนี้จะอยู่ในคลาสอินเตอร์เฟส API ของคุณชื่อSecretApiInterface.java

public interface SecretApiInterface {

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

}

จากนั้นคุณส่งพารามิเตอร์ไปยังอินเทอร์เฟซนี้จากคำขอของคุณบางสิ่งตามบรรทัดเหล่านั้น: (ไฟล์นี้จะเป็นตัวอย่าง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());
    }
}

Somehow.Magically.getToken()การเรียกเมธอดที่ส่งคืนโทเค็นอยู่ที่ไหนมันขึ้นอยู่กับคุณว่าคุณกำหนดไว้ที่ไหนและอย่างไร

แน่นอนคุณสามารถมี@Header("Blah") String blahคำอธิบายประกอบมากกว่าหนึ่งรายการในการใช้งานอินเทอร์เฟซเช่นในกรณีของคุณ!

ฉันพบว่ามันสับสนเช่นกันเอกสารระบุชัดเจนว่ามันแทนที่ส่วนหัว แต่มันไม่ !
ในความเป็นจริงมีการเพิ่มเช่นเดียวกับ@Headers("hardcoded_string_of_liited_use")คำอธิบายประกอบ

หวังว่านี่จะช่วยได้;)


1
ฉันพบในเอกสารว่ามันไม่ได้แทนที่ส่วนหัวที่มีอยู่: "โปรดทราบว่าส่วนหัวจะไม่เขียนทับกัน" ตรวจสอบsquare.github.io/retrofitและ "Header Manipulation"
Amio.io

37

คำตอบที่ยอมรับได้คือ Retrofit เวอร์ชันเก่ากว่า สำหรับผู้ชมในอนาคตวิธีการทำสิ่งนี้ด้วยRetrofit2.0 คือการใช้ไคลเอนต์ OkHttp ที่กำหนดเอง:

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();

หวังว่ามันจะช่วยใครบางคน :)


5
ในการใช้งานทั่วไปกับ dagger2 การติดตั้งเพิ่ม 2 จะเป็นแบบซิงเกิลตันดังนั้น httpclient จะไม่ถูกสร้างขึ้นในแต่ละครั้ง ในกรณีนั้น isUserLoggedIn () ไม่สมเหตุสมผลฉันพูดถูกไหม ทางออกเดียวที่ฉันสามารถเห็นได้ในขณะนี้คือบังคับให้ retrofit2 เริ่มต้นใหม่เมื่อสถานะการเข้าสู่ระบบของผู้ใช้มีการเปลี่ยนแปลงเพื่อให้ส่วนหัวที่เหมาะสมถูกเพิ่มหรือลบออกจากคำขอ .. หรือมีวิธีแก้ไขที่ชัดเจนที่ฉันมองไม่เห็นในขณะนี้ ขอบคุณ.
bajicdusko

2
@bajicdusko นี่คือปริศนาเดียวกันของฉัน คุณพบทางออกแล้วหรือยัง? ดูเหมือนสิ้นเปลืองและแปลกที่เวอร์ชันก่อนหน้านี้มีประสิทธิภาพมากกว่า
โฉนด02392

@date02392 คุณสามารถตั้งค่าคอมโพสิตInterceptorที่คุณสามารถตั้งค่าหรือรีเซ็ตตัวสกัดกั้นในขั้นตอนต่อไป อย่างไรก็ตามฉันขอยืนยันว่าการติดตั้งชุดติดตั้งเพิ่มเติมเป็นซิงเกิลตันอาจเป็นสัญญาณของการเพิ่มประสิทธิภาพในช่วงต้น ไม่มีค่าใช้จ่ายในการสร้างอินสแตนซ์ชุดติดตั้งเพิ่มเติม: github.com/square/retrofit/blob/master/retrofit/src/main/java/…
pablisco

ฉันไม่ได้คิดเกี่ยวกับเรื่องนี้อย่างลึกซึ้ง ฉันมีคลาส ApiFactory ซึ่งเริ่มต้นด้วย dagger2 ด้วยและมีหน้าที่ในการเริ่มต้นการติดตั้งเพิ่มเติม ฉันได้เปิดเผยวิธีการสาธารณะวิธีหนึ่งใน ApiFactory ซึ่งบังคับให้เริ่มต้นอินสแตนซ์การติดตั้งเพิ่มใหม่เมื่อจำเป็นดังนั้นจึงค่อนข้างง่าย ฉันอาจทำผิด แต่มันได้ผลและฉันใช้มันสำหรับส่วนหัวการอนุญาตเท่านั้นดังนั้นจึงใช้เมื่อผู้ใช้เข้าสู่ระบบหรือออกจากระบบ อีกทางเลือกหนึ่งคือใช้คำอธิบายประกอบ @Header ภายในนิยามจุดสิ้นสุดซึ่งไม่เป็นที่ยอมรับสำหรับฉัน ฉันควรตั้งค่าในแต่ละจุดสิ้นสุดซึ่งใช้ไม่ได้จริง
bajicdusko

@pablisco อ่าจากความเข้าใจของฉันคุณไม่สามารถเพิ่มหรือลบInterceptors ได้เมื่อคุณสร้างอินสแตนซ์ Retrofit2
โฉนด02392

7

ชุดติดตั้งเพิ่ม 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();

ฉันใช้สิ่งนี้เพื่อเชื่อมต่อกับ GitHub

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.