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
):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是节省了不少代码。