如何在改造中使用 @Part 传递 header?

how can I pass header using @Part in retrofit?

我的界面是这样的

    @Multipart
    @NonNull
    @FormUrlEncoded
    @POST("upload")
    Call<GeneralResponse> uploadImage(@Header("Authorization") MultipartBody.Part token, @Part("image") MultipartBody.Part image, @Part("kilometer") MultipartBody.Part distance);

上传图片和数据的方法

public void upload(final String token,final String distance, final File image) {

    InternetConnection internetConnection = new InternetConnection(TimeCard.this);
    if (internetConnection.isConnectingToInternet()) {
        showProgressDialog();
        ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);

        MultipartBody.Part bodykm;
        RequestBody kilometer;
        kilometer= RequestBody.create(MediaType.parse("text/plain"), distance);
        bodykm =MultipartBody.Part.createFormData("kilometer", distance, kilometer);


       Call<GeneralResponse> call = apiService.uploadImage(token,bodyImage,bodykm);
        call.enqueue(new Callback<GeneralResponse>() {
            @Override
            public void onResponse(Call<GeneralResponse> call, final Response<GeneralResponse> response) {

                try {
                    if(response.body().getStatus()){

                        meterImage = "";
                        distanceKm = "";
                        Toast.makeText(TimeCard.this,response.body().getMessage(),Toast.LENGTH_LONG).show();
                    }else {
                        Toast.makeText(TimeCard.this,response.body().getMessage(),Toast.LENGTH_LONG).show();
                    }
                }catch (Exception e){
                    progressDialog.dismiss();
                    e.printStackTrace();
                    Toast.makeText(TimeCard.this,e.getMessage(),Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onFailure(Call<GeneralResponse> call, Throwable t) {
                progressDialog.dismiss();
                Toast.makeText(TimeCard.this,"Server error please try again later",Toast.LENGTH_LONG).show();
            }
        });
    } else {
        Toast.makeText(TimeCard.this,"Please check your internet connection",Toast.LENGTH_LONG).show();
    }
}

它给出错误,因为只有一种类型的注释是 allowed.so 我将 @Header 更改为 @Part

@Multipart
    @NonNull
    @FormUrlEncoded
    @POST("upload")
    Call<GeneralResponse> uploadImage(@Part("Authorization") MultipartBody.Part token, @Part("image") MultipartBody.Part image, @Part("kilometer") MultipartBody.Part distance);

现在我怎样才能通过header? (如何将header转换为MultipartBody.Part?)

我先回答你的问题

it gives error because only one type of annotation is allowed

是的,这是 Retrofit 的预期行为。您不能一次使用多个注释。因此,只需从 uploadImage() 方法中删除 @FormUrlEncoded 注释。

现在,您需要 post 距离 以及图像。为此,您应该在 uploadImage() 方法中使用如下所示(在服务 class 中)。

@Part("kilometer") RequestBody distance   // note: use RequestBody instead of MultipartBody.Part

并在 upload() 函数内(在您的 Activity 中)进行更改。

RequestBody kilometer = RequestBody.create(MediaType.parse("text/plain"), distance);

现在进入问题

how can I pass header using @Part in retrofit?

我假设您有动态授权密钥(通过查看相关示例代码)。

如果您在运行时将动态授权密钥设置为 header,您可以使用 Retrofit 的 @HeaderMap 注释。

只需在 uploadImage() 方法中进行以下更改。

@HeaderMap Map<String, String> token

在 Activity 中准备 header 如下图。

Map<String, String> headers = new HashMap<>();
headers.put("Authorization", token);

如果要设置其他 header 参数,请将其设置在同一个 headers 哈希映射中。

然后将此 header 映射传递给您的 uploadImage() 方法。

因此,您的代码中的最终更改如下所示。

您的服务界面

@Multipart
@NonNull
@POST("upload")
Call<GeneralResponse> uploadImage(@HeaderMap Map<String, String> token, @Part("image") MultipartBody.Part image, @Part("kilometer") RequestBody distance);

并在 Activity

public void upload(final String token,final String distance, final File image) {

InternetConnection internetConnection = new InternetConnection(TimeCard.this);
if (internetConnection.isConnectingToInternet()) {
    showProgressDialog();
    ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);

    // prepare distance body
    RequestBody kilometer = RequestBody.create(MediaType.parse("text/plain"), distance);

    // prepare headers
    Map<String, String> headers = new HashMap<>();
    headers.put("Authorization", token);

   Call<GeneralResponse> call = apiService.uploadImage(headers, bodyImage, kilometer);
    call.enqueue(new Callback<GeneralResponse>() {
        @Override
        public void onResponse(Call<GeneralResponse> call, final Response<GeneralResponse> response) {

            try {
                if(response.body().getStatus()){

                    meterImage = "";
                    distanceKm = "";
                    Toast.makeText(TimeCard.this,response.body().getMessage(),Toast.LENGTH_LONG).show();
                }else {
                    Toast.makeText(TimeCard.this,response.body().getMessage(),Toast.LENGTH_LONG).show();
                }
            }catch (Exception e){
                progressDialog.dismiss();
                e.printStackTrace();
                Toast.makeText(TimeCard.this,e.getMessage(),Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call<GeneralResponse> call, Throwable t) {
            progressDialog.dismiss();
            Toast.makeText(TimeCard.this,"Server error please try again later",Toast.LENGTH_LONG).show();
        }
    });
} else {
    Toast.makeText(TimeCard.this,"Please check your internet connection",Toast.LENGTH_LONG).show();
}
}

额外

如果您有静态令牌(每个用户或 API 密钥从不更改的令牌),则无需在此处使用 header 映射模式。直接跳过 @HeaderMap annotation/parameter。进行如下更改。

@Headers("Authorization: your_token_key_here")
@Multipart
@NonNull
@POST("upload")
Call<GeneralResponse> uploadImage(@Part("image") MultipartBody.Part image, @Part("kilometer") RequestBody distance);

同样,如果您有多个 header,请将 header 参数括在 {} 大括号内。

@Headers({
           "Authorization: your_token_key_here",
           "Content-Type: application/json", //  just an example
           "some other header here"
         })
@Multipart
@NonNull
@POST("upload")
Call<GeneralResponse> uploadImage(@Part("image") MultipartBody.Part image, @Part("kilometer") RequestBody distance);