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

ben*_*n10 2 android header multipart retrofit retrofit2

我的界面是这样的

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

上传图片和数据的方法

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它给出了错误,因为只允许一种类型的注释。所以我将 @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);
Run Code Online (Sandbox Code Playgroud)

现在我如何传递标题?(如何将标头转换为 MultipartBody.Part?)

Sha*_*nth 6

我先回答你的问题

它给出错误,因为只允许一种类型的注释

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

现在,您需要与图像一起发布距离。为此,您应该使用如下所示的内部uploadImage()方法(在服务类中)。

@Part("kilometer") RequestBody distance   // note: use RequestBody instead of MultipartBody.Part
Run Code Online (Sandbox Code Playgroud)

内部upload()函数(在您的活动中)进行更改。

RequestBody kilometer = RequestBody.create(MediaType.parse("text/plain"), distance);
Run Code Online (Sandbox Code Playgroud)

现在来回答问题

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

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

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

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

@HeaderMap Map<String, String> token
Run Code Online (Sandbox Code Playgroud)

在 Activity 中准备如下标题映射。

Map<String, String> headers = new HashMap<>();
headers.put("Authorization", token);
Run Code Online (Sandbox Code Playgroud)

如果要设置其他标头参数,请将其设置在相同的标头哈希映射中。

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

因此,您的代码中的最终更改是这样的。

您的服务接口

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

并在活动中

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();
}
}
Run Code Online (Sandbox Code Playgroud)

额外的

如果您有静态令牌(每个用户或 API 密钥永远不会更改的令牌),则无需在此处使用标头映射模式。只需跳过@HeaderMap注释/参数。进行如下更改。

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

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

@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);
Run Code Online (Sandbox Code Playgroud)