Android的HTTP请求方式

本文详细介绍了Android中进行HTTP请求的两种方式:HttpURLConnection和Okhttp。内容涵盖HTTP协议特点、POST与GET的区别,以及Okhttp的优势和使用方法,包括连接超时、参数设置、请求与响应的处理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大多数网络连接的Android应用程序都将使用HTTP发送和接收数据

对于Http协议的工作原理,一句话概括的话,就是客户端向服务器发出一条HTTP请求,服务器收到之后会返回一些数据给客户端,然后客户端再对这些数据进行解析和处理就可以了

HTTP协议的主要特点:

支持客户/服务器模式
简单快速:客户向服务端请求服务时,只需传送请求方式和路径。
灵活:允许传输任意类型的数据对象。由Content-Type加以标记。
无连接:每次响应一个请求,响应完成以后就断开连接。
无状态:服务器不保存浏览器的任何信息。每次提交的请求之间没有关联。

非持续性和持续性:

HTTP1.0默认非持续性;HTTP1.1默认持续性
持续性: 浏览器和服务器建立TCP连接后,可以请求多个对象
非持续性: 浏览器和服务器建立TCP连接后,只能请求一个对象


POST和GET的区别

Post一般用于更新或者添加资源信息 Get一般用于查询操作,而且应该是安全和幂等的
Post更加安全 Get会把请求的信息放到URL的后面
Post传输量一般无大小限制 Get不能大于2KB
Post执行效率低 Get执行效率略高


为什么POST效率低,Get效率高?
Get将参数拼成URL,放到header消息头里传递
Post直接以键值对的形式放到消息体中传递。
但两者的效率差距很小很小

Android系统提供了两种HTTP通信类,HttpURLConnectionHttpClient.两者都支持HTTPS,流式传输上传和下传,可配置超时,IPv6和连接池
关于HttpURLConnection和HttpClient的选择 – 官方推荐博客

不过由于HttpClient存在的API数量过多,扩展困难等缺陷,在开发中也不会推荐使用这种方式。因此在Android M(6.0版本)系统中,HttpClient的功能被完全移除了,标志着此功能被正式弃用,所以今天就介绍一下现在官方建议使用HttpURLConnection的用法.

其实Android4.4的源码中HttpURLConnection已经替换成了OkHttp,这个出色的网络通信库可以完全替代原生的HttpURLConnection,OKHttp是由著名的Square公司开发的,这个公司在开源事业中贡献良多,除了这里说到的OkHttp之外,还有平时常用的像Picasso,Retrofit等著名的开源项目
OKHttp的GitHub主页地址

HttpURLConnection是适用于大多数应用程序的通用轻量级的HTTP客户端,这个阶段发展较为稳重缓慢,但是它的重点API能使我们能够轻松地改进。

在FroyoAndroid2.2版本之前,HttpURLConnection有一些令人沮丧的错误。特别是调用close()可读的InputStream可能会中断连接池.

通过禁用连接池来解决此问题

private void disableConnectionReuseIfNecessary(){
    //HTTP connection reuse which was buggy pre-froyo
    if(Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO){
    System.setProperty("http.keepAlive","false");
    }
}

^(●゚∀゚○)ノ好吧,接下来言归正传,这里从入门开始讲起

入门

首先需要获取到HttpURLConnection的实例,一般只需要new 出一个URL对象,并传入目标的网络地址,然后调用一下openConnection()方法即可,

URL url = new URL("http://blog.youkuaiyun.com/checkiming");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();

在得到了HttpURLConnection的实例之后,可以设置一下HTTP请求所使用的方法。常用的两个方法为: POST和GET .GET表示希望从服务器那里获取到数据,而POST则表示希望提交数据给服务器。

connection.setRequestMethod("GET")
/connection.setRequestMethod("POST")

接下来就可以进行一些自由的定制了,比如设置连接超时、读取超时的毫秒数,以及服务器希望得到的一些消息头等,这部分是可以根据自己的需求情况写的,示例:

connection.setConnectTimeout(6000);
connection.setReadTimeout(6000);
之后再调用getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是对输入流进行读取,如下所示:
InputStream in = connection.getInputStream();
最后可以调用disconnect()这个方法将这个HTTP连接关闭掉,如下显示
connection.disconnect();

即使Google在大部分Android版本推荐建议使用HttpURLConnection ,但在开源盛行的今天,我们完全可以使用一些出色的网络通信库来替代原生的HttpURLConnection ,而OkHttp无疑是最出色的一个。

Okhttp介绍

OkHttp是一个高效的Http客户端,有如下的特点:

支持HTTP2/SPDY黑科技
socket自动选择最好路线,并支持自动重连
拥有自动维护的socket连接池,减少握手次数
拥有队列线程池,轻松写并发
拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
基于Headers的缓存策略

之前也有说到,OKhttp是一个相对成熟的解决方案,在Android4.4的源码中已经将HttpURLConnection替换成了OKhttp,所以我们更有理由去相信OKhttp的强大之处.

OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。

使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。

这里看到一处关于OKhttp的使用问题
注:在国内使用OkHttp会因为这个问题导致部分酷派手机用户无法联网,所以对于大众app来说,需要等待这个bug修复后再使用。或者尝试使用OkHttp的老版本。
截止到目前,OkHttp一直没有修复,并把修复计划延迟到了OkHttp2.3中。不是所有设备都能重现,仅少量设备会出现这个问题。(如果问题这么明显,OkHttp早就修复了)

注意如果使用jar需要导入以下两个包

  1. okhttp3 下载
  2. okio下载

地址

OKhttp官方主页地址

get参数


// 01. 定义okhttp
OkHttpClient okHttpClient_get = new OkHttpClient();
// 02.请求体
Request request = new Request.Builder()
.get()//get请求方式
.url("http://10.0.3.2:8080/WebServiceTest/servlet/ServcieTest?name=sy")//网址
.build();
Response response = okHttpClient_get.newCall(request).execute();
if (response.isSuccessful()) {
    // 打印数据
    System.out.println(response.body().string());
} else {       
     throw new IOException("Unexpected code " + response);
}

-  enqueue是异步方法

post请求参数

// 定义okhttp
OkHttpClient okHttpClient_post_kv = new OkHttpClient();
// 定义请求体
// 执行okhttp
RequestBody body = new FormBody.Builder()
                    .add("name", "sy")//添加参数体
                    .add("age", "18")
                    .build();
Request request = new Request.Builder()
    .post(body) //请求参数
    .url("http://10.0.3.2:8080/WebServiceTest/servlet/ServcieTest")
    .build();
Response response = okHttpClient_post_kv.newCall(request).execute();
System.out.println(response.body().string());


-  enqueue是异步方法

post请求json

OkHttpClient okHttpClient_post_json = new OkHttpClient();
String json = "{\n" + " "age": "18",\n" + " "name": "sy"\n" + "}";
RequestBody body =
RequestBody.create(MediaType.parse("application/json;charset=utf-8"), json);
Request request = new Request.Builder()
.post(body)
.url("http://10.0.3.2:8080/WebServiceTest/servlet/ServcieTest")
.build();
Response response = okHttpClient_post_json.newCall(request).execute();
System.out.println(response.body().string());

上传图片

OkHttpClient okHttpClient_upload = new OkHttpClient();
File file = new File(Environment.getExternalStorageDirectory() + "/download", "file.txt");
RequestBody body = RequestBody.create(MediaType.parse("application/octet-stream"), file);
Request request = new Request.Builder()
    .post(body)
    .url("http://10.0.3.2:8080/WebServiceTest/servlet/ServcieTest")
    .build();
Response response = okHttpClient_upload.newCall(request).execute();
System.out.println(response.body().string());

下载图片

OkHttpClient okHttpClient_down = new OkHttpClient();
Request request =
new Request.Builder()
.get()
.url("http://10.0.3.2:8080/WebServiceTest/p22.jpg")
.build();
okHttpClient_down.newCall(request).enqueue(MainActivity.this);
 /**
 * 超时错误,服务器无响应
 * 
 * @param call
 * @param e
 */
@Override
public void onFailure(Call call, IOException e)
{

}

/**
 * 服务器响应
 * 
 * @param call
 * @param response
 * @throws IOException
 */
@Override
public void onResponse(Call call, Response response)
    throws IOException
{
    InputStream inputStream = response.body().byteStream();
    final BitmapDrawable bitmapDrawable = new BitmapDrawable(inputStream);

    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {

            mIv_main_load_image.setImageDrawable(bitmapDrawable);
        }
    });

}

常用api记录
OkHttpClient client=new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) //设置连接超时
.readTimeout(60, TimeUnit.SECONDS) //设置读超时
.writeTimeout(60,TimeUnit.SECONDS) //设置写超时
.retryOnConnectionFailure(true) //是否自动重连
.build(); //构建OkHttpClient对象
client.dispatcher().executorService().shutdown(); //清除并关闭线程池
client.connectionPool().evictAll(); //清除并关闭连接池
client.cache().close(); //清除cache

用之前的OkHttpClient对象创建一个新的OkHttpClient对象 公用线程池

```
OkHttpClient eagerClient = client.newBuilder() 
.readTimeout(500, TimeUnit.MILLISECONDS)
.build();
Request request = new Request.Builder()

.url(“https://api.github.com/repos/square/okhttpissues“)
//设置访问url
.get() //类似的有post、delete、patch、head、put等方法,对应不同的网络请求方法
.header(“User-Agent”, “OkHttpHeaders.java”) //设置header
.addHeader(“Accept”, “application/json; q=0.5”) //添加header
.removeHeader(“User-Agent”) //移除header
.headers(new Headers.Builder().add(“User-Agent”, “OkHttp Headers.java”).build())//移除原有所有header,并设置新header
.addHeader(“Accept”, “application/vnd.github.v3+json”)
.build(); //构建request

RequestBody还有两个子类:FormBody和MultipartBody。
RequestBody formBody = new FormBody.Builder() //提交表单键值对
.add(“platform”, “android”) //添加键值对
.add(“name”, “XXX”)
.add(“subject”, “Hello”)
.addEncoded(URLEncoder.encode(“详细”,”GBK”), //添加已编码的键值对
URLEncoder.encode(“无”,”GBK”))
.add(“描述”,”你好”) //其实会自动编码,但是无法控制编码格式
.build();

RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addPart(
        Headers.of("Content-Disposition", "form-data; name=\"title\""),
        RequestBody.create(null, "Logo"))
.addPart(
        Headers.of("Content-Disposition", "form-data; name=\"image\""),
        RequestBody.create(MediaType.parse("image/png"), new File("website/static/logo.png")))
.addFormDataPart("discription","beautiful")
.build();
Call对象

Call call=client.newCall(request); //获取Call对象
Response response=call.execute(); //同步执行网络请求,不要在主线程执行
call.enqueue(new Callback()); //异步执行网络请求
call.cancel(); //取消请求
call.isCanceled(); //查询是否取消
call.isExecuted(); //查询是否被执行过
ResponseBody
body.contentLength(); //body的长度
String content=body.string(); //以字符串形式解码body
byte[] byteContent=body.bytes(); //以字节数组形式解码body
InputStreamReader reader=body.charStream(); //将body以字符流的形式解码
InputStream inputStream=body.byteStream(); //将body以字节流的形式解码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值