Android进阶:5、发送post请求、json数据格式以及okhttp框架的使用
1、发送post请求
发送post请求的方式还是跟get有点差别,不过是多了传递表单的操作:
var name:String=et_urlname.text.toString()
var pwd:String=et_urlpwd.text.toString()
//3.1 发送post请求
Thread{
var httpurl: String = "http://10.0.2.2:5000/api/login"
var url: URL = URL(httpurl)
var conn: HttpURLConnection = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.connectTimeout = 5000
conn.readTimeout = 5000
conn.doOutput=true
conn.doInput=true
conn.useCaches=true
var params:String="Email="+URLEncoder.encode(name,"utf-8")
params = params+ "&Password="+URLEncoder.encode(pwd,"utf-8")
var byte:ByteArray=params.toByteArray()
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
conn.setRequestProperty("Connection","Keep-Alive")
conn.setRequestProperty("Content-Length",byte.size.toString())
var os:OutputStream=conn.outputStream
os.write(byte)
os.flush()
os.close()
var code: Int = conn.responseCode
if (code == 200) {
var inputStream: InputStream = conn.inputStream
var byteArray: ByteArray = ByteArray(1024)
var length: Int=0
var result: String = ""
inputStream.use {
length = it.read(byteArray)
result = String(byteArray,0,length)
Log.d(TAG, "$result: ")
if(result.equals("true")){
myhanlder.sendEmptyMessage(1)
}else{
myhanlder.sendEmptyMessage(0)
}
}
inputStream.close()
}
}.start()
跟get的主要区别就是这几个项:
conn.requestMethod = "POST"
conn.connectTimeout = 5000
conn.readTimeout = 5000
conn.doOutput=true
conn.doInput=true
conn.useCaches=true
var params:String="Email="+URLEncoder.encode(name,"utf-8")
params = params+ "&Password="+URLEncoder.encode(pwd,"utf-8")
var byte:ByteArray=params.toByteArray()
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
conn.setRequestProperty("Connection","Keep-Alive")
conn.setRequestProperty("Content-Length",byte.size.toString())
var os:OutputStream=conn.outputStream
os.write(byte)
os.flush()
os.close()
我们先要将请求方式设置为POST,然
后是超时时间和允许输入输出和缓存,因为我们要提交表单,所以我们conn对象的输出流需要将表单写入到缓存里面,就当做是提交了,后面就是制作我们的表单,只需要通过字符串拼接的方式就可以了,后面我们会学习json格式数据,所以这里我们先这样做;再就是一些请求头,比如提交内容的类型Content-Type,为表单类型,链接模式是长连接Keep-Alive,传递的长度就是字节数组的长度,这里都是规定写法;
设置完成了请求头之后就可以将数据写入到缓存,也就是获取conn的输出流,然后write我们拼接好的数据,刷新关闭流就可以了;
后面获取结果的操作都是和get是一样的,这里我们有使用了handler,还是那个使用了弱引用的匿名内部类:
//创建弱引用handler
private class MyHanlder(var wk: WeakReference<HttpPractice>):Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
wk.get()?.run {
if(msg.what==1){
Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show()
}
}
}
}
2、Json数据格式
Android给我们提供了一个简单好用的在对象和json数据格式之间转化的工具,我们需要在项目的builder.gradle下面导入这个依赖(GSON):
implementation 'com.google.code.gson:gson:2.8.6'
然后让项目同步下载一下就可以使用gson这个工具了;json数据格式没有语言的限制,他有自己特定的格式:
又是通过字符串的方式来传递的,所以在网络通讯中有很大的用途;
来总结一下使用HttpURLConnection来访问请求的步骤:
首先我们需要给定一个httpurl也就是网址:
var httpurl: String = "http://10.0.2.2:5000/api/login"
然后就创建一个url对象:
var url: URL = URL(httpurl)
再然后就可以使用这个URL对象来创建一个HttpURLConnection实例:
var conn: HttpURLConnection = url.openConnection() as HttpURLConnection
这样的话就是有了一个请求实例,但是还要配置一些请求的参数:
conn.requestMethod = "POST"
conn.connectTimeout = 5000
conn.readTimeout = 5000
conn.doOutput=true
conn.doInput=true
conn.useCaches=true
这里配置了请求方法为post,请求超时和获取时间都是5秒,然后就是可以读写的操作和开启了缓存;因为post请求一般是需要写入一些数据然后读取一些数据的,比如根据用户的名称和密码我们拿到服务器返回的结果,这个都是通过的读写操作获取,而读写的空间就是缓存区;
要想将表单给服务器,我们就需要使用conn的读写操作:
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
conn.setRequestProperty("Connection","Keep-Alive")
conn.setRequestProperty("Content-Length",byte.size.toString())
var os:OutputStream=conn.outputStream
os.write(byte)
os.flush()
os.close()
这里有设置了提交的数据类型,前面设置的是请求参数,这个就是提交数据的时候需要设置的;
最后拿到了数据时候我们就需要将数据通过流来存下来:
if (code == 200) {
var inputStream: InputStream = conn.inputStream
var byteArray: ByteArray = ByteArray(1024)
var length: Int=0
var result: String = ""
inputStream.use {
length = it.read(byteArray)
result = String(byteArray,0,length)
Log.d(TAG, "$result: ")
if(result.equals("true")){
myhanlder.sendEmptyMessage(1)
}else{
myhanlder.sendEmptyMessage(0)
}
}
inputStream.close()
这里就是使用的conn的输入流,将数据输入到字节数组中,inputSteam.use{}的作用就是判断当inputStream中有数据的时候就执行;
3、okhttp请求框架
这是一个安卓很常用的网络请求框架,其实不仅仅是安卓可以,java、Python同样是可以使用这个网络框架,他主要实现的功能就是发送网络请求,不过要比安卓自带的HttpURLConnection方便得多:
Thread(){
var client:OkHttpClient= OkHttpClient()
var request: Request=Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build()
client.newCall(request).execute().use {
response ->
if(!response.isSuccessful){
throw IOException("Unexpected code$response")
}
for((name,value) in response.headers){
Log.d(TAG, "okhttplogin: $name:$value")
}
Log.d(TAG, "run: "+response.body!!.string())
}
}.start()
注意:在使用这个框架之前我们需要导入依赖,或者可以自己离线导入jar包,但是离线需要导入okhttp和okio两个jar包;
导入依赖:
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
配合之前设置好的user-permssion权限就可以了;
它大概只需要三步就可以完成一个请求的发送和接收,而HttpURLConnection不仅要设置很多参数,还需使用输入输出流来进行数据的接收和发送;那么是那三步呢?
1)、创建okhttpclient客户机和request请求对象;
var client:OkHttpClient= OkHttpClient()
var request: Request=Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build()
这里默认发送的是get请求,我们还可以是表单和json:
json:
//1.2 异步的发送json数据
var jsonobject:JSONObject= JSONObject()
var name:String=et_name.text.toString()
var pwd:String=et_pwd.text.toString()
jsonobject.put("UserName",name)
jsonobject.put("UserPwd",pwd)
var client:OkHttpClient= OkHttpClient()
var request: Request=Request.Builder()
.url("http://10.0.2.2:8080/api/v2/user_login")
.post(jsonstr)
.build()
表单:
var client:OkHttpClient= OkHttpClient()
var formBody=FormBody.Builder()
.add("Email","tt@gmail.com")
.add("Password","123456")
.build()
var request: Request=Request.Builder()
.url("http://10.0.2.2:5000//api/login")
.post(formBody)
.build()
2)、发送请求
client.newCall(request).execute().use {
response ->
}
3)、接收处理数据
if(!response.isSuccessful){
throw IOException("Unexpected code$response")
}
for((name,value) in response.headers){
Log.d(TAG, "okhttplogin: $name:$value")
}
Log.d(TAG, "run: "+response.body!!.string())
使用OKhttp框架发送请求的时候是不一样的,他不需要设置太多参数和表头数据,一般就三步:
var client:OkHttpClient= OkHttpClient()
var request: Request=Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build()
client.newCall(request).execute().use {
response ->
if(!response.isSuccessful){
throw IOException("Unexpected code$response")
}
for((name,value) in response.headers){
Log.d(TAG, "okhttplogin: $name:$value")
}
Log.d(TAG, "run: "+response.body!!.string())
}
创建一个okhttpclient实例,这个实例是用来发送请求的,但是需要传递一个request参数,而我们需要在request参数创建的时候给定网址和类型,默认的就是get请求;request对象的实例是链式创建的,可以看到一般后面要跟上.build();
而且client还可以指定同步和异步请求:
//同步发送
client.newCall(request).execute().use {
response ->
}
//异步发送
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
/*TODO("Not yet implemented")*/
Log.d(TAG, "onFailure: 请求失败 ${e.message}")
}
override fun onResponse(call: Call, response: Response) {
//TODO("Not yet implemented")
if (!response.isSuccessful) {
throw IOException("Unexpected code 请求出错")
}
Log.d(TAG, "run: " + response.body?.string())
myhanlder.sendEmptyMessage(1)
}
同步请求的话只需要在response后面处理数据就可以了:
client.newCall(request).execute().use {
response ->
if(!response.isSuccessful){
throw IOException("Unexpected code$response")
}
for((name,value) in response.headers){
Log.d(TAG, "okhttplogin: $name:$value")
}
Log.d(TAG, "run: "+response.body!!.string())
}
而异步的话是具有两个函数(onFailure/onResponse)的,是实现的接口的一个是请求失败的,一个是获取到了数据的;
了解了这三步之后我们就可以发送各种请求了:
json:
var jsonobject:JSONObject= JSONObject()
var name:String=et_name.text.toString()
var pwd:String=et_pwd.text.toString()
jsonobject.put("UserName",name)
jsonobject.put("UserPwd",pwd)
Log.d(TAG, "okdown:$name + $pwd ")
var jsonstr=jsonobject.toString().toRequestBody("application/json;charset=utf-8".toMediaType())
Thread(){
var client:OkHttpClient= OkHttpClient()
var request: Request=Request.Builder()
.url("http://10.0.2.2:8080/api/v2/user_login")
.post(jsonstr)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
/*TODO("Not yet implemented")*/
Log.d(TAG, "onFailure: 请求失败:${e.message}")
}
override fun onResponse(call: Call, response: Response) {
//TODO("Not yet implemented")
if (!response.isSuccessful) {
throw IOException("Unexpected code$response")
}
var jsonObject: JSONObject = JSONObject(response.body!!.string())
Log.d(TAG, "onResponse: ${jsonObject.get("RESULT")}")
//Log.d(TAG, "run: " + response.body!!.string())
}
})
}.start()
表单:
//发送表单请求
Thread(){
var client:OkHttpClient= OkHttpClient()
var formBody=FormBody.Builder()
.add("Email","tt@gmail.com")
.add("Password","123456")
.build()
var request: Request=Request.Builder()
.url("http://10.0.2.2:5000/api/login")
.post(formBody)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
/*TODO("Not yet implemented")*/
Log.d(TAG, "onFailure: 请求失败 ${e.message}")
}
override fun onResponse(call: Call, response: Response) {
//TODO("Not yet implemented")
if (!response.isSuccessful) {
throw IOException("Unexpected code 请求出错")
}
Log.d(TAG, "run: " + response.body?.string())
myhanlder.sendEmptyMessage(1)
}
})
}.start()
而这两者之间最大的区别就是提交的数据格式不同:
json:
jsonobject.put("UserName",name)
jsonobject.put("UserPwd",pwd)
Log.d(TAG, "okdown:$name + $pwd ")
var jsonstr=jsonobject.toString().toRequestBody("application/json;charset=utf-8".toMediaType())
就是通过上面编码出来的json字符串放到post属性里面:
var request: Request=Request.Builder()
.url("http://10.0.2.2:8080/api/v2/user_login")
.post(jsonstr)
.build()
表单操作也是一样的:
var formBody=FormBody.Builder()
.add("Email","tt@gmail.com")
.add("Password","123456")
.build()
var request: Request=Request.Builder()
.url("http://10.0.2.2:5000/api/login")
.post(formBody)
.build()
但是相比HttpURLConnection是节省了不少代码。
更多推荐
所有评论(0)