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","[email protected]")
.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","[email protected]")
                .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","[email protected]")
                .add("Password","123456")
                .build()
            var request: Request=Request.Builder()
                .url("http://10.0.2.2:5000/api/login")
                .post(formBody)
                .build()

但是相比HttpURLConnection是节省了不少代码。

猜你喜欢

转载自blog.csdn.net/aiwanchengxu/article/details/127941351
今日推荐