目录
OkHttp的介绍
添加依赖
OkHttp的使用
get的同步与异步请求
post的同步与异步请求
POST请求的数据格式
POST请求上传文件
POST请求上传json对象
POST请求上传多个数据
OkHttp的配置
1.Builder构建器
2.自定义拦截器
3.自定义缓存
4. 自定义Cookie
https://square.github.io/okhttp/
由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.0开始HttpURLConnection的底层实现采用的是OkHttp
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
上述依赖会自动下载okhttp库和okio库
记得添加权限!
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请求的基本步骤:
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提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式。而常用的数据编码方式有:
注意:
String、ByteArray、ByteString转RequestBody都用toRequestBody()
而File转RequestBody用asRequestBody()
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()
}
}
}
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()
}
}
}
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()
}
}
}
val okHttpClient:OkHttpClient=OkHttpClient.Builder().build()
可以加入一些自己配置的小配件
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()
}
}
}
OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需要进行同样的请求,此时如果符合缓存规则,则可以减少与服务器的网络通信,直接从本地文件缓存中读取响应放回给请求者。但是在默认情况下,OkHttp的缓存是关闭状态,需要我们开启。
Cache(缓存文件地址,缓存最大容量字节)
val okHttpClient:OkHttpClient=OkHttpClient.Builder()
.cache(Cache(File(externalCacheDir,"a"),1024*1024))
.build()
Cookie是某个网站为了辨别用户身份,进行会话跟踪(比如确定登录状态)而存储在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。
我们在玩Android - wanandroid.com - 每日推荐优质文章
这个网站上注册账号,然后得到账号和密码。这个网站提供很多接口。
请求登录接口之后将返回cookie保存下来,才能请求其他接口,这里请求的是收藏列表。
fun cookietest(){
val cookies = HashMap>()
thread {
val okHttpClient:OkHttpClient=OkHttpClient.Builder().cookieJar(object :CookieJar{ //加载并保存cookie
override fun loadForRequest(url: HttpUrl): List {
val cookies: List? = cookies.get(url.host)
if(cookies==null)
return ArrayList()
else {
return cookies
}
}
//保存cookie
override fun saveFromResponse(url: HttpUrl, list: List) {
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()
}
}
}