• Android进阶:5、发送post请求、json数据格式以及okhttp框架的使用


    1、发送post请求

    发送post请求的方式还是跟get有点差别,不过是多了传递表单的操作:

    1. var name:String=et_urlname.text.toString()
    2.        var pwd:String=et_urlpwd.text.toString()
    3.        //3.1 发送post请求
    4.        Thread{
    5.            var httpurl: String = "http://10.0.2.2:5000/api/login"
    6.            var url: URL = URL(httpurl)
    7.            var conn: HttpURLConnection = url.openConnection() as HttpURLConnection
    8.            conn.requestMethod = "POST"
    9.            conn.connectTimeout = 5000
    10.            conn.readTimeout = 5000
    11.            conn.doOutput=true
    12.            conn.doInput=true
    13.            conn.useCaches=true
    14.            var params:String="Email="+URLEncoder.encode(name,"utf-8")
    15.            params = params+ "&Password="+URLEncoder.encode(pwd,"utf-8")
    16.            var byte:ByteArray=params.toByteArray()
    17.            conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
    18.            conn.setRequestProperty("Connection","Keep-Alive")
    19.            conn.setRequestProperty("Content-Length",byte.size.toString())
    20.            var os:OutputStream=conn.outputStream
    21.            os.write(byte)
    22.            os.flush()
    23.            os.close()
    24.            var code: Int = conn.responseCode
    25.            if (code == 200) {
    26.                var inputStream: InputStream = conn.inputStream
    27.                var byteArray: ByteArray = ByteArray(1024)
    28.                var length: Int=0
    29.                var result: String = ""
    30.                inputStream.use {
    31.                    length = it.read(byteArray)
    32.                    result = String(byteArray,0,length)
    33.                    Log.d(TAG, "$result: ")
    34.                    if(result.equals("true")){
    35.                        myhanlder.sendEmptyMessage(1)
    36.                   }else{
    37.                        myhanlder.sendEmptyMessage(0)
    38.                   }
    39.               }
    40.                inputStream.close()
    41.           }
    42.       }.start()

    跟get的主要区别就是这几个项:

    1. conn.requestMethod = "POST"
    2.            conn.connectTimeout = 5000
    3.            conn.readTimeout = 5000
    4.            conn.doOutput=true
    5.            conn.doInput=true
    6.            conn.useCaches=true
    7.            var params:String="Email="+URLEncoder.encode(name,"utf-8")
    8.            params = params+ "&Password="+URLEncoder.encode(pwd,"utf-8")
    9.            var byte:ByteArray=params.toByteArray()
    10.            conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
    11.            conn.setRequestProperty("Connection","Keep-Alive")
    12.            conn.setRequestProperty("Content-Length",byte.size.toString())
    13.            var os:OutputStream=conn.outputStream
    14.            os.write(byte)
    15.            os.flush()
    16.            os.close()

    我们先要将请求方式设置为POST,然

    后是超时时间和允许输入输出和缓存,因为我们要提交表单,所以我们conn对象的输出流需要将表单写入到缓存里面,就当做是提交了,后面就是制作我们的表单,只需要通过字符串拼接的方式就可以了,后面我们会学习json格式数据,所以这里我们先这样做;再就是一些请求头,比如提交内容的类型Content-Type,为表单类型,链接模式是长连接Keep-Alive,传递的长度就是字节数组的长度,这里都是规定写法;

    设置完成了请求头之后就可以将数据写入到缓存,也就是获取conn的输出流,然后write我们拼接好的数据,刷新关闭流就可以了;

    后面获取结果的操作都是和get是一样的,这里我们有使用了handler,还是那个使用了弱引用的匿名内部类

    1. //创建弱引用handler
    2.    private class MyHanlder(var wk: WeakReference):Handler(Looper.getMainLooper()){
    3.        override fun handleMessage(msg: Message) {
    4.            super.handleMessage(msg)
    5.            wk.get()?.run {
    6.                if(msg.what==1){
    7.                    Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show()
    8.               }else{
    9.                    Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show()
    10.               }
    11.           }
    12.       }
    13.   }

    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

    这样的话就是有了一个请求实例,但是还要配置一些请求的参数:

    1. conn.requestMethod = "POST"
    2. conn.connectTimeout = 5000
    3. conn.readTimeout = 5000
    4. conn.doOutput=true
    5. conn.doInput=true
    6. conn.useCaches=true

    这里配置了请求方法为post,请求超时和获取时间都是5秒,然后就是可以读写的操作和开启了缓存;因为post请求一般是需要写入一些数据然后读取一些数据的,比如根据用户的名称和密码我们拿到服务器返回的结果,这个都是通过的读写操作获取,而读写的空间就是缓存区;

    要想将表单给服务器,我们就需要使用conn的读写操作:

    1. conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded")
    2. conn.setRequestProperty("Connection","Keep-Alive")
    3. conn.setRequestProperty("Content-Length",byte.size.toString())
    4. var os:OutputStream=conn.outputStream
    5. os.write(byte)
    6. os.flush()
    7. os.close()

    这里有设置了提交的数据类型,前面设置的是请求参数,这个就是提交数据的时候需要设置的;

    最后拿到了数据时候我们就需要将数据通过流来存下来:

    1. if (code == 200) {
    2. var inputStream: InputStream = conn.inputStream
    3. var byteArray: ByteArray = ByteArray(1024)
    4. var length: Int=0
    5. var result: String = ""
    6. inputStream.use {
    7. length = it.read(byteArray)
    8. result = String(byteArray,0,length)
    9. Log.d(TAG, "$result: ")
    10. if(result.equals("true")){
    11. myhanlder.sendEmptyMessage(1)
    12. }else{
    13. myhanlder.sendEmptyMessage(0)
    14. }
    15. }
    16. inputStream.close()

    这里就是使用的conn的输入流,将数据输入到字节数组中,inputSteam.use{}的作用就是判断当inputStream中有数据的时候就执行;

    3、okhttp请求框架

    这是一个安卓很常用的网络请求框架,其实不仅仅是安卓可以,java、Python同样是可以使用这个网络框架,他主要实现的功能就是发送网络请求,不过要比安卓自带的HttpURLConnection方便得多:

    1. Thread(){
    2.            var client:OkHttpClient= OkHttpClient()
    3.            var request: Request=Request.Builder()
    4.               .url("https://publicobject.com/helloworld.txt")
    5.               .build()
    6.            client.newCall(request).execute().use {
    7.                response ->
    8.                if(!response.isSuccessful){
    9.                    throw IOException("Unexpected code$response")
    10.               }
    11.                for((name,value) in response.headers){
    12.                    Log.d(TAG, "okhttplogin: $name:$value")
    13.               }
    14.                Log.d(TAG, "run: "+response.body!!.string())
    15.           }
    16.       }.start()

    注意:在使用这个框架之前我们需要导入依赖,或者可以自己离线导入jar包,但是离线需要导入okhttp和okio两个jar包;

    导入依赖:

    implementation 'com.squareup.okhttp3:okhttp:4.9.0'

    配合之前设置好的user-permssion权限就可以了;

    它大概只需要三步就可以完成一个请求的发送和接收,而HttpURLConnection不仅要设置很多参数,还需使用输入输出流来进行数据的接收和发送;那么是那三步呢?

    1)、创建okhttpclient客户机和request请求对象;

    1. var client:OkHttpClient= OkHttpClient()
    2. var request: Request=Request.Builder()
    3. .url("https://publicobject.com/helloworld.txt")
    4. .build()

    这里默认发送的是get请求,我们还可以是表单和json:

    json:

    1. //1.2 异步的发送json数据
    2. var jsonobject:JSONObject= JSONObject()
    3. var name:String=et_name.text.toString()
    4. var pwd:String=et_pwd.text.toString()
    5. jsonobject.put("UserName",name)
    6. jsonobject.put("UserPwd",pwd)
    7. var client:OkHttpClient= OkHttpClient()
    8. var request: Request=Request.Builder()
    9. .url("http://10.0.2.2:8080/api/v2/user_login")
    10. .post(jsonstr)
    11. .build()

    表单:

    1. var client:OkHttpClient= OkHttpClient()
    2. var formBody=FormBody.Builder()
    3. .add("Email","tt@gmail.com")
    4. .add("Password","123456")
    5. .build()
    6. var request: Request=Request.Builder()
    7. .url("http://10.0.2.2:5000//api/login")
    8. .post(formBody)
    9. .build()

    2)、发送请求

    1. client.newCall(request).execute().use {
    2.               response ->
    3.                
    4.           }

    3)、接收处理数据

    1. if(!response.isSuccessful){
    2. throw IOException("Unexpected code$response")
    3. }
    4. for((name,value) in response.headers){
    5. Log.d(TAG, "okhttplogin: $name:$value")
    6. }
    7. Log.d(TAG, "run: "+response.body!!.string())

    使用OKhttp框架发送请求的时候是不一样的,他不需要设置太多参数和表头数据,一般就三步:

    1. var client:OkHttpClient= OkHttpClient()
    2. var request: Request=Request.Builder()
    3. .url("https://publicobject.com/helloworld.txt")
    4. .build()
    5. client.newCall(request).execute().use {
    6. response ->
    7. if(!response.isSuccessful){
    8. throw IOException("Unexpected code$response")
    9. }
    10. for((name,value) in response.headers){
    11. Log.d(TAG, "okhttplogin: $name:$value")
    12. }
    13. Log.d(TAG, "run: "+response.body!!.string())
    14. }

    创建一个okhttpclient实例,这个实例是用来发送请求的,但是需要传递一个request参数,而我们需要在request参数创建的时候给定网址和类型,默认的就是get请求;request对象的实例是链式创建的,可以看到一般后面要跟上.build();

    而且client还可以指定同步和异步请求:

    1. //同步发送
    2. client.newCall(request).execute().use {
    3. response ->
    4. }
    5. //异步发送
    6. client.newCall(request).enqueue(object : Callback {
    7. override fun onFailure(call: Call, e: IOException) {
    8. /*TODO("Not yet implemented")*/
    9. Log.d(TAG, "onFailure: 请求失败 ${e.message}")
    10. }
    11. override fun onResponse(call: Call, response: Response) {
    12. //TODO("Not yet implemented")
    13. if (!response.isSuccessful) {
    14. throw IOException("Unexpected code 请求出错")
    15. }
    16. Log.d(TAG, "run: " + response.body?.string())
    17. myhanlder.sendEmptyMessage(1)
    18. }

    同步请求的话只需要在response后面处理数据就可以了:

    1. client.newCall(request).execute().use {
    2. response ->
    3. if(!response.isSuccessful){
    4. throw IOException("Unexpected code$response")
    5. }
    6. for((name,value) in response.headers){
    7. Log.d(TAG, "okhttplogin: $name:$value")
    8. }
    9. Log.d(TAG, "run: "+response.body!!.string())
    10. }

    而异步的话是具有两个函数(onFailure/onResponse)的,是实现的接口的一个是请求失败的,一个是获取到了数据的;

    了解了这三步之后我们就可以发送各种请求了:

    json:

    1. var jsonobject:JSONObject= JSONObject()
    2.        var name:String=et_name.text.toString()
    3.        var pwd:String=et_pwd.text.toString()
    4.        jsonobject.put("UserName",name)
    5.        jsonobject.put("UserPwd",pwd)
    6.        Log.d(TAG, "okdown:$name + $pwd ")
    7.        var jsonstr=jsonobject.toString().toRequestBody("application/json;charset=utf-8".toMediaType())
    8.        Thread(){
    9.            var client:OkHttpClient= OkHttpClient()
    10.            var request: Request=Request.Builder()
    11.               .url("http://10.0.2.2:8080/api/v2/user_login")
    12.               .post(jsonstr)
    13.               .build()
    14.            client.newCall(request).enqueue(object : Callback {
    15.                override fun onFailure(call: Call, e: IOException) {
    16.                    /*TODO("Not yet implemented")*/
    17.                    Log.d(TAG, "onFailure: 请求失败:${e.message}")
    18.               }
    19.                override fun onResponse(call: Call, response: Response) {
    20.                    //TODO("Not yet implemented")
    21.                    if (!response.isSuccessful) {
    22.                        throw IOException("Unexpected code$response")
    23.                   }
    24.                    var jsonObject: JSONObject = JSONObject(response.body!!.string())
    25.                    Log.d(TAG, "onResponse: ${jsonObject.get("RESULT")}")
    26.                    //Log.d(TAG, "run: " + response.body!!.string())
    27.               }
    28.           })
    29.       }.start()

    表单:

    1. //发送表单请求
    2.        Thread(){
    3.            var client:OkHttpClient= OkHttpClient()
    4.            var formBody=FormBody.Builder()
    5.               .add("Email","tt@gmail.com")
    6.               .add("Password","123456")
    7.               .build()
    8.            var request: Request=Request.Builder()
    9.               .url("http://10.0.2.2:5000/api/login")
    10.               .post(formBody)
    11.               .build()
    12.            client.newCall(request).enqueue(object : Callback {
    13.                override fun onFailure(call: Call, e: IOException) {
    14.                    /*TODO("Not yet implemented")*/
    15.                    Log.d(TAG, "onFailure: 请求失败 ${e.message}")
    16.               }
    17.                override fun onResponse(call: Call, response: Response) {
    18.                    //TODO("Not yet implemented")
    19.                    if (!response.isSuccessful) {
    20.                        throw IOException("Unexpected code 请求出错")
    21.                   }
    22.                    Log.d(TAG, "run: " + response.body?.string())
    23.                    myhanlder.sendEmptyMessage(1)
    24.               }
    25.           })
    26.       }.start()

    而这两者之间最大的区别就是提交的数据格式不同:

    json:

    1. jsonobject.put("UserName",name)
    2. jsonobject.put("UserPwd",pwd)
    3. Log.d(TAG, "okdown:$name + $pwd ")
    4. var jsonstr=jsonobject.toString().toRequestBody("application/json;charset=utf-8".toMediaType())

    就是通过上面编码出来的json字符串放到post属性里面:

    1. var request: Request=Request.Builder()
    2. .url("http://10.0.2.2:8080/api/v2/user_login")
    3. .post(jsonstr)
    4. .build()

    表单操作也是一样的:

    1. var formBody=FormBody.Builder()
    2. .add("Email","tt@gmail.com")
    3. .add("Password","123456")
    4. .build()
    5. var request: Request=Request.Builder()
    6. .url("http://10.0.2.2:5000/api/login")
    7. .post(formBody)
    8. .build()

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

  • 相关阅读:
    nrm 镜像源管理工具
    Kotlin高仿微信-第25篇-朋友圈-显示列表
    (十)再探反向传播和神经网络优化
    【Linux 驱动基础】驱动程序基石
    npm install 卡在reify:rxjs: timing reifyNode的解决办法
    VBA 剪切板
    对系统的 Go 版本进行升级
    有意思的开源项目分享(持续更新,勤劳的搬运工,只放一些我感兴趣的)
    Redis阅读——内存分配
    FPGA解析B码----连载7(完结篇)
  • 原文地址:https://blog.csdn.net/aiwanchengxu/article/details/127941351