Android学习笔记:OkHttp3的基本使用之Post请求

用Okhttp已有一段时日,奈何,自我感觉依旧处于多脸懵逼的状态,遂提笔画记一番。


目录

一、添加依赖

二、构建okhttp的实例

三、配置RequestBody请求体

四、配置Request请求

五、配置Call

六、提交(字符串)请求

七、请看网络请求结果,传Log!

八、其实

九、POST提交文件      

十、POST提交表单          

十一、提交分块请求

十二、完整代码


一、添加依赖

     首先。你得先知道ok的最新版本。也就是去OK的github的老窝看下

              https://github.com/square/okhttp

      然后,去app/build.gradle 添加相应的依赖

      类似这个:

dependencies {
    implementation "com.squareup.okhttp3:okhttp:3.14.0"}

二、构建okhttp的实例

         嗯。正题,okhttp怎么用?先得弄个实例出来,有三种方式,三种之间的区别已在注释中倾述:

    private HttpUtil() {
        //第一种.通过配置ok的各种功能,来构建它的实例,就像组装电脑一样
        okHttpClient = new OkHttpClient.Builder()
                //连接超时
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                //读取超时
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                //写超时
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                //拦截器
                .addInterceptor(new LoggingInterceptor()).build();
        //第二种.通过现有实例去创建一个实例
        okHttpClient=okHttpClient.newBuilder().build();
        //第三种.默认构造创建实例
        okHttpClient=new OkHttpClient();
        //这三种的区别是:稍后更精彩,哈哈哈
    }

三、配置RequestBody请求体

        和上一篇get请求的类似,但除了要配置访问地址外,还要添加点东西,啥呢,它就是你想要上缴给服务器的东西,人称请求体,专业术语是----RequestBody , 只要你按照一定的规则往RequestBody 里丢东西,它就可以帮你合成服务器想要的样子。所以,首先你得搞个RequestBody 出来,然后,将你要给服务器的数据requestContent,以及你的数据类型mediaType是属于文本类型还是其他,RequestBody 的构建代码:

        /**
         *  1.MediaType对象包含了三种信息:type - 数据基础类型 、subtype - 数据子类型 以及 charset - 字符编码
         *  (1)text,表示是文本这一大类
         *  (2)x-markdown是subtype,表示是文本这一大类下的markdown这一小类
         *  (3)charset=utf-8 则表示采用UTF-8编码
         */
        MediaType mediaType=MediaType.parse("text/x-markdown;charset=utf-8");
        /**
         * 2.要提提交的数据内容
         */
        String requestContent="I am kk";
        /**
         * 3.合成请求体
         */
        RequestBody requestBody=RequestBody.create(mediaType,requestContent);

四、配置Request请求

          RequestBody 搞出来后,需要配置到 Request 里,同时记得加上要访问的服务器地址,Request 的构建代码:

        //要访问的地址
        String url="https://api.github.com/markdown/raw";
        //构建Request
        Request request=new Request.Builder()
                .url(url)
                //这是刚刚新鲜出炉的请求体
                .post(requestBody)
                .build();

五、配置Call

           Call 是个接口,接口里有两方法专门搞网络请求,真正的引用则是它的实现类RealCall ,new Call 只是把RealCall实例给父类接口Call变量,当然,这是后话。看代码解释可以发现。

    A call is a request that has been prepared for execution.// Call是一个已准备好执行的请求 
          

             构建代码:

         Call call=okHttpClient.newCall(request);

 

六、提交(字符串)请求

          Call 的enqueue方法是异步的,所以,你可C以暂且忽略由网络各类情况可能造成的堵塞问题,它内部会处理好的。当然,还有一个execute 方法,但它是同步的,会阻塞主线程,所以,本回打入冷宫。

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d("onFailure getMessage"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() "+response.body().string()
                        +"\n response.code() "+response.code()
                        +"\n response.message() "+response.message());
                Headers headers=response.headers();
                for (int i = 0; i < headers.size(); i++) {
                    GyLog.d(""+headers.name(i)+":"+headers.value(i));
                }
            }
        });

七、请看网络请求结果,传Log!

           对于下面的一些Http 报文结构,可以参考 HTTP请求/响应报文结构 来进行更深入的了解


2019-04-02 14:03:38.959 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:132):  response.body() = 

I am kk

//响应内容 2019-04-02 14:03:38.959 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:133): response.code() = 200 //响应码 2019-04-02 14:03:38.960 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:134): response.message() = OK //响应信息 2019-04-02 14:03:38.960 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Date:Tue, 02 Apr 2019 06:03:36 GMT //响应时间 2019-04-02 14:03:38.960 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Content-Type:text/html;charset=utf-8 //内容格式;字符编码 2019-04-02 14:03:38.960 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Content-Length:15 //内容长度 2019-04-02 14:03:38.961 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Server:GitHub.com //服务器的类型 2019-04-02 14:03:38.961 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Status:200 OK //状态码 2019-04-02 14:03:38.961 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-RateLimit-Limit:60 //同一个时间段所允许的请求的最大数目 2019-04-02 14:03:38.961 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-RateLimit-Remaining:57 //在当前时间段内剩余的请求的数量 2019-04-02 14:03:38.962 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-RateLimit-Reset:1554188536 //为了得到最大请求数所等待的秒数 2019-04-02 14:03:38.963 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-CommonMarker-Version:0.18.1 2019-04-02 14:03:38.963 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Access-Control-Expose-Headers:ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type 2019-04-02 14:03:38.963 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Access-Control-Allow-Origin:* 2019-04-02 14:03:38.963 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Strict-Transport-Security:max-age=31536000; includeSubdomains; preload 2019-04-02 14:03:38.964 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-Frame-Options:deny 2019-04-02 14:03:38.964 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-Content-Type-Options:nosniff 2019-04-02 14:03:38.965 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-XSS-Protection:1; mode=block 2019-04-02 14:03:38.965 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Referrer-Policy:origin-when-cross-origin, strict-origin-when-cross-origin 2019-04-02 14:03:38.966 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Content-Security-Policy:default-src 'none' 2019-04-02 14:03:38.966 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): Vary:Accept-Encoding 2019-04-02 14:03:38.966 31743-31787/com.gc.testhttp D/Kabun:HttpUtil$2.onResponse(L:137): X-GitHub-Request-Id:A859:0CA7:178F025:1F48D9A:5CA2FB37

八、其实

         以上的提交是属于post请求中的提交 String 字符串的方式,post可以提交的内容还包括以下几种:

  1. 提交String字符串  
  2. 提交ByteString字节字符串
  3. 提交byte[]字节数组
  4. 提交byte[]字节数组,并指定了在数组的起始位置以及元素数量
  5. 提交文件
  6. .....

                                          Android学习笔记:OkHttp3的基本使用之Post请求_第1张图片

九、POST提交文件      

          找到文件的位置,就能把文件操作对象搞出来,随后,把文件对象放到request里即可。提交文件示例代码:

        MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        OkHttpClient okHttpClient = new OkHttpClient();
        //构建指定文件实例
        File file = new File("/storage/emulated/0/test.txt");
        Request request = new Request.Builder()
                .url("https://api.github.com/markdown/raw")
                //传入文件实例
                .post(RequestBody.create(mediaType, file))
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });

          提交文件响应结果 Log:

2019-04-02 16:41:35.111 28136-28181/com.gc.testhttp D/Kabun:HttpUtil$5.onResponse(L:225):  response.body() = 

test 123456

2019-04-02 16:41:35.112 28136-28181/com.gc.testhttp D/Kabun:HttpUtil$5.onResponse(L:226): response.code() = 200 2019-04-02 16:41:35.112 28136-28181/com.gc.testhttp D/Kabun:HttpUtil$5.onResponse(L:227): response.message() = OK

十、POST提交表单          

           提交表单的话,首先要弄个表单出来,你会发现,少了个MediaType,即之前的内容类型,这个呢是因为FormBody里面已经配置了它,即系封装,关于MediaType的知识可以参考  MediaType

public final class FormBody extends RequestBody {
  private static final MediaType CONTENT_TYPE = MediaType.get("application/x-www-form-urlencoded");

           表单一般要 key 和 value  ,就像 key=“姓名”,value = “小三”  ,噢不 ,value = “张三”。然后,你会发现,FormBody实例可以赋值给RequestBody变量,这是因为FormBodyRequestBody的儿子,子类

        OkHttpClient okHttpClient = new OkHttpClient();
        //注意:FormBody 类已经内置了静态常量来表示这个body的数据内容类型属于 application/x-www-form-urlencoded
        //所以,不用另外设置 MediaType
        RequestBody requestBody = new FormBody.Builder()
                //类似左边键名,右边键值
                .add("search", "Jurassic Park")
                .build();
        Request request = new Request.Builder()
                .url("https://en.wikipedia.org/w/index.php")
                .post(requestBody)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });

              请求结果就不贴了,因为返回的结果是一个HTML网页代码。

十一、提交分块请求

         首先得说下啥是分块,之前的那些都是一个请求块一个请求块那样往服务器丢,这个分块呢,就是,咳咳,就是多几个请求块,堆在一起,一块儿浪。分块的核心东西类是-----MultipartBody,名字就已经透露出一种分块之气,MultipartBody是RequestBody的子类,MultipartBody最爽的地方是,它可以多个请求体一块提交,例如提交多个文件如图片之类的上服务器。

        MultipartBody的构建方式有以下几种:

                                                Android学习笔记:OkHttp3的基本使用之Post请求_第2张图片

         尝试使用上图第二行的方式构建,代码示例:

        MultipartBody multipartBody=new MultipartBody.Builder("AaB03x")
                //就是设置 MimeType
                .setType(MultipartBody.FORM)
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"title\""),
                        RequestBody.create(null, "Square Logo"))
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"image\""),
                        RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
                .build();

            但是,在源码里,归根到底,最后还是调用 addPart(Part part) 的方法,然后形成一个 List。又由于, Part 是由 头部信息Header 和 请求体 RequestBody组成,所以说,MultipartBody 只是将多个头部信息Header 和 请求体 RequestBody合成一个列表。

            MultipartBody构建完成后,按照以往套路,放进Request 里进行构建:

        Request request = new Request.Builder()
                .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
                .url("https://api.imgur.com/3/image")
                .post(multipartBody)
                .build();
      然后再按部就班的进行一系列操作:
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });

十二、完整代码

public class HttpUtil {
    private static final long WRITE_TIMEOUT = 30;
    private static final long READ_TIMEOUT = 30;
    private static final long CONNECT_TIMEOUT = 30;
    String url = "http://wwww.baidu.com";
    private OkHttpClient okHttpClient;

    private HttpUtil() {
        //1.通过配置ok的各种功能,来构建它的实例,就像组装电脑一样
        okHttpClient = new OkHttpClient.Builder()
                //连接超时
                .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                //读取超时
                .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                //写超时
                .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                //拦截器:
                .addInterceptor(new LoggingInterceptor()).build();
//        //2.通过现有实例去创建一个实例
//        okHttpClient=okHttpClient.newBuilder().build();
//        //3.默认构造创建实例
//        okHttpClient=new OkHttpClient();
    }

    public static class Builder {
        public static HttpUtil build() {
            return new HttpUtil();
        }

    }


    /**
     * POST 方式提交String
     */
    public void postString(){

        /**
         *  1.MediaType对象包含了三种信息:type - 数据基础类型 、subtype - 数据子类型 以及 charset - 字符编码
         *  (1)text,表示是文本这一大类
         *  (2)x-markdown是subtype,表示是文本这一大类下的markdown这一小类
         *  (3)charset=utf-8 则表示采用UTF-8编码
         */
        MediaType mediaType=MediaType.parse("text/x-markdown;charset=utf-8");
        /**
         * 2.要提提交的数据内容
         */
        String requestContent="I am kk";
        /**
         * 3.合成请求体
         */
        RequestBody requestBody=RequestBody.create(mediaType,requestContent);
        //要访问的地址
        String url="https://api.github.com/markdown/raw";
        Request request=new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d("onFailure getMessage"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
                GyLog.d(" response.protocol() = "+response.protocol());
                Headers headers=response.headers();
                for (int i = 0; i < headers.size(); i++) {
                    GyLog.d(""+headers.name(i)+":"+headers.value(i));
                }
            }
        });
    }


    /**
     * 提交流
     */
    public void postSink(){
        /**
         *  1.MediaType对象包含了三种信息:type - 数据基础类型 、subtype - 数据子类型 以及 charset - 字符编码
         *  (1)text,表示是文本这一大类
         *  (2)x-markdown是subtype,表示是文本这一大类下的markdown这一小类
         *  (3)charset=utf-8 则表示采用UTF-8编码
         */
        MediaType mediaType=MediaType.parse("text/x-markdown;charset=utf-8");
        /**
         * 2.要提提交的数据内容
         */
        String requestContent="I am kk";
        /**
         * 3.合成请求体
         */
        RequestBody requestBody=new RequestBody() {
            @Override
            public MediaType contentType() {
                return mediaType;
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.writeUtf8(requestContent);
            }
        };
        //要访问的地址
        String url="https://api.github.com/markdown/raw";
        Request request=new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d("onFailure getMessage"+e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
                GyLog.d(" response.protocol() = "+response.protocol());
                Headers headers=response.headers();
                for (int i = 0; i < headers.size(); i++) {
                    GyLog.d(""+headers.name(i)+":"+headers.value(i));
                }
            }
        });
    }

    /**
     * 提交文件
     */
    public void postFile(){
        MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
        OkHttpClient okHttpClient = new OkHttpClient();
        //构建指定文件实例
        File file = new File("/storage/emulated/0/test.txt");
        Request request = new Request.Builder()
                .url("https://api.github.com/markdown/raw")
                //传入文件实例
                .post(RequestBody.create(mediaType, file))
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });
    }

    /**
     * 提交表单
     */
    public void postFormBody(){
        OkHttpClient okHttpClient = new OkHttpClient();
        //注意:FormBody 类已经内置了静态常量来表示这个body的数据内容类型属于 application/x-www-form-urlencoded
        //所以,不用另外设置 MediaType
        RequestBody requestBody = new FormBody.Builder()
                //类似左边键名,右边键值
                .add("search", "Jurassic Park")
                .build();
        Request request = new Request.Builder()
                .url("https://en.wikipedia.org/w/index.php")
                .post(requestBody)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });
    }

    /**
     * 提交分块
     */
    public void postMultiPartBody(){
        String IMGUR_CLIENT_ID = "...";
        MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
        OkHttpClient okHttpClient = new OkHttpClient();
        MultipartBody multipartBody=new MultipartBody.Builder("AaB03x")
                .setType(MultipartBody.FORM)
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"title\""),
                        RequestBody.create(null, "Square Logo"))
                .addPart(
                        Headers.of("Content-Disposition", "form-data; name=\"image\""),
                        RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
                .build();
        Request request = new Request.Builder()
                .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
                .url("https://api.imgur.com/3/image")
                .post(multipartBody)
                .build();
        Call call=okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                GyLog.d( "onFailure: " + e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                GyLog.d(" response.body() = "+response.body().string());
                GyLog.d(" response.code() = "+response.code());
                GyLog.d(" response.message() = "+response.message());
            }
        });
    }
}

      到目前为止,这是okhttp最基本的POST请求用法,图谱如下:

 Android学习笔记:OkHttp3的基本使用之Post请求_第3张图片

       参考文章: Okhttp3基本使用

你可能感兴趣的:(网络交互,android)