OkHttp是一个高效的HTTP库:


支持 SPDY ,共享同一个 Socket 来处理同一个服务器的所有请求

如果 SPDY 不可用,则通过连接池来减少请求延时

无缝的支持GZIP来减少数据流量

缓存响应数据来减少重复的网络请求


OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。


OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。


1、HTTP请求方法

同步GET请求

privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{Requestrequest=newRequest.Builder().url("http://publicobject.com/helloworld.txt").build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);HeadersresponseHeaders=response.headers();for(inti=0;i<responseHeaders.size();i++){System.out.println(responseHeaders.name(i)+":"+responseHeaders.value(i));}System.out.println(response.body().string());}

Response类的string()方法会把文档的所有内容加载到内存,适用于小文档,对应大于1M的文档,应 使用流()的方式获取。

response.body().byteStream()

异步GET请求

privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{Requestrequest=newRequest.Builder().url("http://publicobject.com/helloworld.txt").build();client.newCall(request).enqueue(newCallback(){@OverridepublicvoidonFailure(Requestrequest,IOExceptione){e.printStackTrace();}@OverridepublicvoidonResponse(Responseresponse)throwsIOException{if(!response.isSuccessful()){thrownewIOException("Unexpectedcode"+response);}HeadersresponseHeaders=response.headers();for(inti=0;i<responseHeaders.size();i++){System.out.println(responseHeaders.name(i)+":"+responseHeaders.value(i));}System.out.println(response.body().string());}});}

读取响应会阻塞当前线程,所以发起请求是在主线程,回调的内容在非主线程中。

POST方式提交字符串

privatestaticfinalMediaTypeMEDIA_TYPE_MARKDOWN=MediaType.parse("text/x-markdown;charset=utf-8");privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{StringpostBody=""+"Releases\n"+"--------\n"+"\n"+"*_1.0_May6,2013\n"+"*_1.1_June15,2013\n"+"*_1.2_August11,2013\n";Requestrequest=newRequest.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN,postBody)).build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);System.out.println(response.body().string());}

因为整个请求体都在内存中,应避免提交1M以上的文件。

POST方式提交流

privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{RequestBodyrequestBody=newRequestBody(){@OverridepublicMediaTypecontentType(){returnMEDIA_TYPE_MARKDOWN;}@OverridepublicvoidwriteTo(BufferedSinksink)throwsIOException{sink.writeUtf8("Numbers\n");sink.writeUtf8("-------\n");for(inti=2;i<=997;i++){sink.writeUtf8(String.format("*%s=%s\n",i,factor(i)));}}privateStringfactor(intn){for(inti=2;i<n;i++){intx=n/i;if(x*i==n)returnfactor(x)+"×"+i;}returnInteger.toString(n);}};Requestrequest=newRequest.Builder().url("https://api.github.com/markdown/raw").post(requestBody).build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);System.out.println(response.body().string());}

使用Okio框架以流的形式将内容写入,这种方式不会出现内存溢出问题。

POST方式提交文件

publicstaticfinalMediaTypeMEDIA_TYPE_MARKDOWN=MediaType.parse("text/x-markdown;charset=utf-8");privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{Filefile=newFile("README.md");Requestrequest=newRequest.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN,file)).build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);System.out.println(response.body().string());}

POST方式提交表单

privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{RequestBodyformBody=newFormEncodingBuilder().add("search","JurassicPark").build();Requestrequest=newRequest.Builder().url("https://en.wikipedia.org/w/index.php").post(formBody).build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);System.out.println(response.body().string());}

表单的每个Names-Values都进行了URL编码。如果服务器端接口未进行URL编码,可定制个 FormBuilder。

文件上传(兼容html文件上传)

privatestaticfinalStringIMGUR_CLIENT_ID="...";privatestaticfinalMediaTypeMEDIA_TYPE_PNG=MediaType.parse("p_w_picpath/png");privatefinalOkHttpClientclient=newOkHttpClient();publicvoidrun()throwsException{//Usetheimgurp_w_picpathuploadAPIasdocumentedathttps://cache.yisu.com/upload/information/20200311/46/200136.jpg"))).build();Requestrequest=newRequest.Builder().header("Authorization","Client-ID"+IMGUR_CLIENT_ID).url("https://api.imgur.com/3/p_w_picpath").post(requestBody).build();Responseresponse=client.newCall(request).execute();if(!response.isSuccessful())thrownewIOException("Unexpectedcode"+response);System.out.println(response.body().string());}