Android Http文件上传方法和实践

文件上传在应用中是比较常用的的一种功能,比如用户的意见反馈功能。用户可以上传图片,音视频等文件,方便用户反馈问题的情况。

下来我将和大家一起梳理下需要掌握的知识,少走弯路一步到位,实现文件上传功能。

第一步:了解请求头

需要先大致了解一下上传信息需要的请求结构。当我们掌握了请求头的结构,就可以根据自己项目情况选择sdk或者自己实现HTTP请求。

使用HTTP进行文件上传需要用到POST请求。POST请求包含请求Head 和请求Body。

上传文件需要使用 Content-type为multipart/form-data 的格式,发送请求信息。这种格式的数据会有一个边界线用于分割不同的字段。如下文中的:boundary=86489a0c-3d1f-4351-8f49-58315690babe

请求Head: 一般会携带客户端的一些信息包括签名,token等。服务端用这些信息来校验是否合法。

请求Body: 会携带文件的信息和相关的参数便于服务端进行区分。

消息头可以携带签名信息等字段,用于服务端校验。请求头中的 head1 和head2,代表token,uuid,key等信息用于校验。


POST https://*****/upload
Content-Type: multipart/form-data; boundary=86489a0c-3d1f-4351-8f49-58315690babe
Content-Length: 83014
head1: param
head2: param

消息主体以分界线开始,紧接着就是内容描述信息,可以携带多个字段进行资源数据的描述。最后是字段具体的内容(文本或二进制)。

请求体中的param1 和param2 代表携带文件的相关参数信息,比如文件扩展名等,方便服务端进行区分

--86489a0c-3d1f-4351-8f49-58315690babe
Content-Disposition: form-data; name="param1"
Content-Length: 8
param1

--86489a0c-3d1f-4351-8f49-58315690babe
Content-Disposition: form-data; name="param2"
Content-Length: 3
param2

--86489a0c-3d1f-4351-8f49-58315690babe
Content-Disposition: form-data; name="file"; filename="pic.png"
Content-Type: application/otcet-stream
Content-Length: 82560
*****

--86489a0c-3d1f-4351-8f49-58315690babe

消息主体以boundary结束。

第二步:实践

我们将用目前比较流行的框架实现上面的结构。为了方便了解,我会一一对应的结构,实现上面的Post接口,实际应用中可以充分利用框架的进行接口优化。

方案1:直接使用OKHttp 上传文件

        File file= new File(file);

        // 构建okhttpclient,使用HttpLoggingInterceptor 打印调试日志
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        clientBuilder.connectTimeout(Config.DEFAULT_TIMEOUT, TimeUnit.SECONDS);
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        clientBuilder.addInterceptor(loggingInterceptor);
        OkHttpClient client = clientBuilder.build();


        // 构造请求头
        Headers.Builder headerBuilder =  new Headers.Builder();
        headerBuilder.add("head1","***");
        headerBuilder.add("head2","***");
        

        // 构造请求体
        MultipartBody.Builder builder = new MultipartBody.Builder();
        builder.setType(MultipartBody.FORM);
        
        
        builder.addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"param1\""),
                        RequestBody.create(null, "param1"));
                        

        builder.addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"param2\""),
                        RequestBody.create(null, "param2"));

        MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
        RequestBody filebody = MultipartBody.create(MEDIA_TYPE_PNG, file);
        builder.addFormDataPart("file",file.getName(),filebody);

        MultipartBody body = builder.build();

        // 构造请求
        Request request = new Request.Builder()
                .headers(headerBuilder.build())
                .url("***********")
                .post(body)
                .build();

        // 发起请求
        Call call = client.newCall(request);
        call.enqueue(new Callback() {


            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

            }
        });

方案2:利用Retrofit 上传文件

实例化Retroift 对象

        // 构造okhttp
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        clientBuilder.connectTimeout(Config.DEFAULT_TIMEOUT, TimeUnit.SECONDS);

        // 打印网络请求日志
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        clientBuilder.addInterceptor(loggingInterceptor);

        mOkHttpClient = httpClientBuilder.build();
        
        // 构造Retrofit
        mRetrofit = new Retrofit.Builder()
                .client(mOkHttpClient)
                .baseUrl(BASE_URL)
                // 增加 Gson转换
                .addConverterFactory(GsonConverterFactory.create())
                .build();

定义Retrofit接口

        @Multipart
        @POST("***")
        Call uploadFile(@Header("head1") String head1,
                                  @Header("head2") String head2,
                                  @Part MultipartBody.Part param1,
                                  @Part MultipartBody.Part param2,
                                  @Part MultipartBody.Part multipartBody);
                                  
                                  
    

调用Retrofit接口

        mApiService = NetworkService.getInstance().getService(Api.class);

        //请求体
        MultipartBody.Part param1 = MultipartBody.Part.createFormData("param1", "param1");
        MultipartBody.Part param2 = MultipartBody.Part.createFormData("param2", "param2");

        File file = new File("path");
        RequestBody body = RequestBody.create(MediaType.parse("application/otcet-stream"), file);
        MultipartBody.Part filebody = MultipartBody.Part.createFormData("file",file.getName(),body);

        call = mApiService.uploadFile("head1","head2",param1,param2,filebody);
        call.enqueue(new Callback() {
            @Override
            public void onResponse(Call call, 

            }

            @Override
            public void onFailure(Call call, Throwable t) {

            }
        });

调试工具

对于在家没有后端支持的同学,可以使用 Http File Server 在局域网类部署服务端,然后进行接口测试。
Http File Server 工具可以在百度上搜到,使用的中可以关闭用户校验功能。

你可能感兴趣的:(Android Http文件上传方法和实践)