OkHttp的介绍
由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.0开始HttpURLConnection的底层实现采用的是OkHttp
添加依赖
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
上述依赖会自动下载okhttp库和okio库
OkHttp的使用
记得添加权限!
<uses-permission android:name="android.permission.INTERNET" />
get的同步与异步请求
get请求的基本步骤:
1.创建OkHttpClient的实例
2.创建Request对象,设置url地址
3.创建Call对象,调用它的execute方法(同步)或者enqueue方法(异步)来发送请求并获取服务器返回的数据
4.得到服务器返回的数据的具体内容
get同步请求
//get同步请求 fun getSync() { thread { try { val client = OkHttpClient() val request = Request.Builder() .url("https://www.httpbin.org/get?a=1&b=2") .build() val call=client.newCall(request) val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码 val requestData = response.body?.string() if (requestData != null) { Log.e("getSync", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
get异步请求
//get异步请求 fun getAsync(){ val client = OkHttpClient() val request = Request.Builder() .url("https://www.httpbin.org/get?a=1&b=2") .build() val call=client.newCall(request) //异步请求,enqueue方法不会阻塞后续代码的执行 call.enqueue(object :Callback{ //请求失败调用 override fun onFailure(call: Call, e: IOException) { } //请求结束调用(意味着与服务器的通信成功) override fun onResponse(call: Call, response: Response) { if(response.isSuccessful){ response.body?.let { Log.e("getAsync", it.string()) } } } }) }
响应码在200到299之间就是成功的。
post的同步与异步请求
post请求的基本步骤:
1.创建OkHttpClient的实例
2.创建RequestBody对象来存放待提交的参数
2.创建Request对象,设置url地址,调用post方法,把RequestBody对象传入
3.创建Call对象,调用它的execute方法(同步)或者enqueue方法(异步)来发送请求并获取服务器返回的数据
4.得到服务器返回的数据的具体内容
post同步请求提交键值对
//post同步请求 fun postSync(){ thread { try { val client = OkHttpClient() val requestBody=FormBody.Builder().add("a","1").add("b","2").build() val request = Request.Builder() .url("https://www.httpbin.org/post") .post(requestBody) .build() val call=client.newCall(request) val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码 val requestData = response.body?.string() if (requestData != null) { Log.e("postSync", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
post异步请求提交键值对
//post异步请求 fun postAsync(){ val client = OkHttpClient() val requestBody=FormBody.Builder().add("a","1").add("b","2").build() val request = Request.Builder() .url("https://www.httpbin.org/post") .post(requestBody) .build() val call=client.newCall(request) //异步请求,enqueue方法不会阻塞后续代码的执行 call.enqueue(object :Callback{ //请求失败调用 override fun onFailure(call: Call, e: IOException) { } //请求结束调用(意味着与服务器的通信成功,) override fun onResponse(call: Call, response: Response) { if(response.isSuccessful){ response.body?.let { Log.e("postAsync", it.string()) } } } }) }
POST请求的数据格式
协议规定POST提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式。而常用的数据编码方式有:
- application/x-www-form-urlencoded:默认, key1=value1&key2=value2
- multipart/form-data:一般用于表单需要文件上传
- .application/json:提交json数据
- text/plain:将文件设置为纯文本的形式
- application/octet-stream:提交二进制数据,如果用于文件上传,只能上传一个文件
注意:
String、ByteArray、ByteString转RequestBody都用toRequestBody()
而File转RequestBody用asRequestBody()
POST请求上传文件
fun Filetest(){ thread { try { val client = OkHttpClient() //创建文件 val file1=File(externalCacheDir,"jfApp") if (!file1.exists()){ file1.createNewFile(); } //在file1中写入aaa file1.printWriter().use { out-> out.println("aaa") } //把file转化为RequestBody val fileBody1=file1.asRequestBody("text/plain".toMediaType()) val request = Request.Builder() .url("https://www.httpbin.org/post") .post(fileBody1) .build() val call=client.newCall(request) val response = call.execute() val requestData = response.body?.string() if (requestData != null) { Log.e("file", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
POST请求上传json对象
fun jsontest(){ thread { try { val client = OkHttpClient() val json:String="{\"a\":1,\"b\":2}" val requestBody=json.toRequestBody("application/json".toMediaType()) val request = Request.Builder() .url("https://www.httpbin.org/post") .post(requestBody) .build() val call=client.newCall(request) val response = call.execute() val requestData = response.body?.string() if (requestData != null) { Log.e("jsontext", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
POST请求上传多个数据
fun Filetest(){ thread { try { val client = OkHttpClient() //创建文件 val file1=File(externalCacheDir,"jfApp") val file2=File(externalCacheDir,"jfApp2") if (!file1.exists()){ file1.createNewFile(); } if (!file2.exists()){ file2.createNewFile(); } //在file1中写入aaa file1.printWriter().use { out-> out.println("aaa") } //把file转化为RequestBody val fileBody1=file1.asRequestBody("text/plain".toMediaType()) val fileBody2=file2.asRequestBody("text/plain".toMediaType()) //把数据放入multipartBody中 val multipartBody = MultipartBody.Builder() .addFormDataPart("file1", file1.name,fileBody1)//添加文件 .addFormDataPart("file2",file2.name,fileBody2) .addFormDataPart("a","1")//添加键值对 .build() val request = Request.Builder() .url("https://www.httpbin.org/post") .post(multipartBody) .build() val call=client.newCall(request) val response = call.execute() val requestData = response.body?.string() if (requestData != null) { Log.e("file", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
OkHttp的配置
1.Builder构建器
val okHttpClient:OkHttpClient=OkHttpClient.Builder().build()
可以加入一些自己配置的小配件
2.自定义拦截器
okhttp的拦截器就是在intercept(chain: Interceptor.Chain)的回调中对Request和Response进行修改,然后通过chain.proceed(request)调起下一个拦截器。
val okHttpClient:OkHttpClient=OkHttpClient.Builder().addInterceptor(xxx).build()
val okHttpClient:OkHttpClient=OkHttpClient.Builder().addNetworkInterceptor(xxx).build()
addInterceptor()和addNetworkInterceptor()的区别:
1.addInterceptor()的优先级高于addNetworkInterceptor()。
2.在1的条件下,添加拦截器的的顺序就是执行的顺序。
在拦截器中修改Request添加请求头,就可以在每个Request对象中自动添加请求头,减少麻烦。
fun interceptor(){ thread { try { val okHttpClient:OkHttpClient=OkHttpClient.Builder() .addInterceptor(object : Interceptor{ override fun intercept(chain: Interceptor.Chain): Response { //前置处理 val request=chain.request().newBuilder() .addHeader("os","android") .addHeader("version","1.0").build() val response=chain.proceed(request) //后置处理 return response } }) .build() val request = Request.Builder() .url("https://www.httpbin.org/get?a=1&b=2") .build() val call=okHttpClient.newCall(request) val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码 val requestData = response.body?.string() if (requestData != null) { Log.e("getSync", requestData) } } catch (e: Exception) { e.printStackTrace() } } }
3.自定义缓存
OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需要进行同样的请求,此时如果符合缓存规则,则可以减少与服务器的网络通信,直接从本地文件缓存中读取响应放回给请求者。但是在默认情况下,OkHttp的缓存是关闭状态,需要我们开启。
Cache(缓存文件地址,缓存最大容量字节)
val okHttpClient:OkHttpClient=OkHttpClient.Builder() .cache(Cache(File(externalCacheDir,"a"),1024*1024)) .build()
4. 自定义Cookie
Cookie是某个网站为了辨别用户身份,进行会话跟踪(比如确定登录状态)而存储在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
我们在玩Android - wanandroid.com - 每日推荐优质文章
这个网站上注册账号,然后得到账号和密码。这个网站提供很多接口。
请求登录接口之后将返回cookie保存下来,才能请求其他接口,这里请求的是收藏列表。
fun cookietest(){ val cookies = HashMap<String,List<Cookie>>() thread { val okHttpClient:OkHttpClient=OkHttpClient.Builder().cookieJar(object :CookieJar{ //加载并保存cookie override fun loadForRequest(url: HttpUrl): List<Cookie> { val cookies: List<Cookie>? = cookies.get(url.host) if(cookies==null) return ArrayList<Cookie>() else { return cookies } } //保存cookie override fun saveFromResponse(url: HttpUrl, list: List<Cookie>) { cookies.put(url.host,list) } }).build() val fromBody=FormBody.Builder().add("username","xxx") .add("password","xxx").build()//网站的账号和密码 var request = Request.Builder() .url("https://www.wanandroid.com/user/login") .post(fromBody) .build() var call=okHttpClient.newCall(request) try { val response = call.execute() val requestData = response.body?.string() if (requestData != null) { Log.e("cookietest", requestData) } } catch (e: Exception) { e.printStackTrace() } request=Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json") .build() call=okHttpClient.newCall(request) try { val Response=call.execute() Response.body?.let { Log.e("cookietest", it.string()) } }catch (e:Exception){ e.printStackTrace() } } }