当前位置: 首页 > news >正文

Android http网络请求的那些事儿

1.http协议

http协议通常是基于TCP/IT协议之上的应用层协议,http默认端口是80,https默认端口是443
http协议是无状态的协议,基于请求/响应的模型,先有请求,再有响应。
http请求报文包括:请求行、请求头、请求体
http响应报文包括:响应行、响应头、响应体

2.http请求报文结构

在这里插入图片描述

  • 请求行
    主要包括请求方式以及请求目标的URL
    例如:POST /chapter17/user.html HTTP/1.1

    POST代表请求方式, /chapter17/user.html表示请求的URL

  • 请求头
    包含一些key-value值,主要包括Cookie值、请求体的数据类型、请求体的数据长度等例如:
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 37
    Cookie: token_pass=92595c118b66417c395eb125e12c3438

  • 请求体
    具体的数据,比如登陆时候的用户名和密码:
    username=gandalf&password=19920930yus

3.http不同请求方式

请求方式有多种,常见的有GETPOSTHEAD

  • GET请求
    GET请求没有请求体,会把参数直接加在URL后面,不安全,并且有长度限制。
    但请求简单,是HTTP请求中使用最多的方式。

  • POST请求
    请求的参数在请求头内,较安全,且数据大小没有限制,适合提交较大的表单数据。

  • HEAD请求
    跟GET相似,只是服务器只会返回响应头,通常只为了查询某个页面的状态。

4.http响应报文结构

在这里插入图片描述

  • 响应行
    主要包含状态码
    1xx:指示信息,表示请求已接收,继续处理
    2xx:成功,表示请求已被成功接受
    3xx:重定向
    4xx:客户端错误
    5xx:服务器端错误

  • 响应头
    包含多个key-value对,主要包括:Content-Type响应正文的类型(MIME类型)、Set-Cookie 于会话状态相关的Cookie技术

  • 响应体
    数据内容,常用的如json纯文本内容、图片数据等

5.https协议

由于http是明文传输,信息容易被篡改和窃取,所以增加了https协议。
https协议是在http协议的基础上,对报文做了对称加密的处理,并且加密密钥只会在客户端和服务端保存,保证了信息的安全。
https协议的前提,是需要有一个公正权威的机构,叫CA机构,它内部维护了一套非对称加密的公钥P私钥P',公钥P会发布出来,浏览器会内置这个公钥。
一个网站如果要使用https协议,需要先在CA申请数字证书。

6.https协议加密过程

前置条件完毕,接下来看具体的步骤:

  1. 首先网站有一对公钥P1私钥P1’,然后把包含网站公钥P1、域名等信息的数据Data提供给CA机构。
  2. CA对Data做Hash算法得到一段散列码H;用P’对H做加密得到数字签名S;把S和Data数据打包一起就是数字证书,给到网站。
  3. 客户端和服务端建立http连接之后,服务端会把数字证书发给客户端。客户端会得到数字签名S和原始数据Data,然后使用CA的公钥P对S解密得到散列码H
  4. 客户端会对Data做同样的hash算法得到散列码H',判断H’和H是否相等,如果相等,则表示公钥P1是可信的。
  5. 客户端会针对此次对话随机生成一个对称加密密钥SK,并使用P1对SK信息做加密,传递给服务器。
  6. 服务器在收到客户端数据后,使用自己的私钥P1’做解码,获取到了本次的SK,并开始做加密通信。

流程图如下:
在这里插入图片描述

  • 关键点补充
    CA的存在是为了保证客户端判断来自服务器公钥的可靠性。
    前期非对称加密的一系列动作,是为了保证最后对称加密的密钥不能被第三方获取。
    最后通信数据使用对称加密(AES),是因为非对称加密很耗性能,而对称加密效率更高。

7.Cookie

由于http/https是没有状态的协议,整个过程是请求/应答模式,而有些数据的请求是需要有状态的,比如:
请求收藏列表数据,那么肯定是需要先登陆才行,否则就会提示:

{"errorCode":-1001,"errorMsg":"请先登录!"}

因此引入了Cookie技术。
首先服务端会在响应头中带有Set-Cookie 字段的数据,当客户端解析到这样的响应头数据时,就可以把这些数据保存在本地。
当客户端下次要发起请求的时候,就可以把这些Cookie写入到请求头中,这样服务端就可以清楚状态并返回正确的数据了。
比如我们登陆了WanAndroid账号之后,服务端返回的响应报文头包含:

Set-Cookie: JSESSIONID=354B46332F155D0823934D17025C01CB; Path=/; Secure; HttpOnly
Set-Cookie: loginUserName=gandalf; Expires=Fri, 12-Dec-2025 07:00:21 GMT; Path=/
Set-Cookie: token_pass=92595c118b66417c395eb125e12c3438; Expires=Fri, 12-Dec-2025 07:00:21 GMT; Path=/
Set-Cookie: loginUserName_wanandroid_com=gandalf; Domain=wanandroid.com; Expires=Fri, 12-Dec-2025 07:00:21 GMT; Path=/
Set-Cookie: token_pass_wanandroid_com=92595c118b66417c395eb125e12c3438; Domain=wanandroid.com; Expires=Fri, 12-Dec-2025 07:00:21 GMT; Path=/

当我们请求收藏数据的时候,就需要把以上的Cookie信息带上,这样就会获取到收藏列表数据了,否则就会提示“请先登录!”。

8.OkHttp

Android使用http网络协议的利器,它负责处理HTTP/1.1HTTP/2SPDY的请求和响应,可以理解为一个装备精良的“快递员”。
OkHttp 负责处理所有网络通信的底层脏活累活:

  • 通过连接池 ConnectionPool,高效地复用 TCP 连接;
  • socket自动选择最好路线,并支持自动重连;
  • 拥有队列线程池,轻松写并发,支持同步和异步两种请求方式;
  • 拥有强大的拦截器机制(interceptors),可以轻松修改请求报文和响应报文,比如统一修改请求头、日志记录、加解密、Cookie缓存等。

9.OkHttp的执行流程

  1. 首先需要构造一个OkHttpClient客户端,并且在客户端配置相关的拦截器和监听器,以便扩展自定义的操作。
  2. 构建Request请求类,包含URLPost参数等信息。
  3. 然后通过OkHttpClient客户端去构建一个Call类型的对象,代表一次请求。Call有两个方法,一个方法是execute(),表示同步执行请求;
    另一个方法是enqueue(),表示把请求加入队列,实际会进入到Dispatcher的runningAsyncCalls这样的一个队列,并等待异步执行。
  4. 不管是同步执行还是异步执行,在执行的时候,都会先构建一个拦截器链(RealInterceptorChain),它会add很多默认的或者我们自定义的拦截器。
  5. 一个拦截器执行完之后,会调用下一个拦截器,直到调用到最后一个CallServiceInterceptor并返回一个Response

10.OkHttp使用示例

只使用OkHttp的情况下,如果我们要发起一次登陆请求,则代码如下:

// 1. 创建客户端
val client = OkHttpClient()// 2. 手动构建请求 (URL, 请求头, 请求体)
val requestBody = FormBody.Builder().add("username", "gandalf").add("password", "1234567").build()val request = Request.Builder().url("https://api.example.com/login").post(requestBody).build()// 3. 发起异步请求,并手动处理回调
client.newCall(request).enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {// 处理网络失败}override fun onResponse(call: Call, response: Response) {// 在子线程中val responseBodyString = response.body?.string()// 4. 手动解析 JSON 字符串val user = Gson().fromJson(responseBodyString, User::class.java)// 5. 手动切换回主线程更新 UI}
})

这里创建的OkHttpClient客户端是最简单的方式,如果想要添加其他配置项,比如Cookie的操作、http日志打印操作等,就需要在这里做配置:

private val intercepter = HttpLoggingInterceptor().apply {level = HttpLoggingInterceptor.Level.BODY}private val okhttpClient = OkHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS)   // 读超时时间.writeTimeout(30, TimeUnit.SECONDS)  // 写超时时间.connectTimeout(30, TimeUnit.SECONDS) //连接超时时间.addInterceptor(intercepter)  // 添加日志打印的拦截器.cookieJar(MyCookieJar()) //添加Cookie操作.build()

这里实现了CookieJar接口:

class MyCookieJar : CookieJar {//Http发送请求前回调,Request中设置Cookieoverride fun loadForRequest(url: HttpUrl): List<Cookie> {val cookieList = mutableListOf<Cookie>()CookieManager.getInstance().getCookie(url.host)?.let {if (it.isNotEmpty()) {val cookies = it.split(";".toRegex())for (cookie in cookies) {Cookie.parse(url, cookie)?.apply {cookieList.add(this)}}}}return cookieList}//Http请求结束,Response中有Cookie时候回调,并在回调中实现Cookie的保存override fun saveFromResponse(url: HttpUrl,cookies: List<Cookie>) {val cookieManager = CookieManager.getInstance()cookieManager.setAcceptCookie(true)for (cookie in cookies) {cookieManager.setCookie(url.toString(), cookie.toString())}cookieManager.flush()}
}

11. Retrofit

Retrofit是一种更高层级的封装,它让开发者更容易去描述“做什么”。而它自己会把这些业务层的逻辑转换成OkHttp能够识别的指令,具体“怎么做”的事情,就交给OkHttp去完成。
Retrofit的优势有如下几点:

  1. API接口化:使用简单的Interface接口来定义一组业务关系API。
  2. 注解驱动:通过 @GET``````@POST, @Path, @Query, @Body 等注解,你可以清晰地描述每个请求的 URL、HTTP 方法、参数和请求体
  3. 序列化/反序列化:通过可自由配置的转换器(Converter),如retrofit2:converter-gson,自动将 对象转换成请求体JSON,以及将响应体JSON自动转换成定义好的数据模型对象(Data Class)。
  4. 适配协程:能将标准的网络调用无缝集成到协程框架中

基本使用方式如下:

// 1. 在接口中声明 API
interface ApiService {@POST("login")@FormUrlEncodedsuspend fun login(@Field("username") username: String): User
}// 2. 创建 Retrofit 实例 (它内部会持有并使用一个 OkHttpClient)
val retrofit = Retrofit.Builder().baseUrl("https://api.example.com/").client(myOkHttpClient) // 把 OkHttp 引擎装进去.addConverterFactory(GsonConverterFactory.create()).build()val apiService = retrofit.create(ApiService::class.java)// 3. 在协程中像调用本地方法一样调用 API
viewModelScope.launch {try {val user = apiService.login("test")  // 直接得到 User 对象,不用关心 JSON 解析和线程切换} catch (e: Exception) {// 统一处理所有错误}
}
http://www.dtcms.com/a/605730.html

相关文章:

  • 两台 centos 7.9 部署 pbs version 18.1.4 集群
  • 【动手学深度学习】8.1. 序列模型
  • 【AI软件开发】从文献管理到知识编织:构建AI驱动的学术研究工作流
  • 网站上面图片上传尺寸建设部二级结构工程师注销网站
  • PostIn从初级到进阶(3) - 如何对接口快速设计并管理接口文档
  • 按键精灵安卓/ios脚本开发辅助工具:yolo转换教程
  • 人工智能驱动下的OCR API技术演进与实践应用
  • 昆明网站建设介绍湛江专业雷剧全集
  • 网站到期时间营销型网站服务公司
  • 常用设计模式:工厂方法模式
  • 视频矩阵哪个品牌好?2025 视频矩阵品牌标杆出炉
  • MongoDB 分片
  • 网站访客qq获取苏州建网站公司
  • Vue 3与 Vue 2响应式的区别
  • 自主建站平台怎样在百度建网站
  • 开源白板工具(SaaS),一体化白板,包含思维导图、流程图、自由画等
  • 九、InnoDB引擎-MVCC
  • Cesium 性能优化:从常识到深入实践
  • 购物网站的排版番禺品牌型网站建设
  • 想学习网站建设网络公司起名大全最新
  • claude 国内注册方法(2025 年 11 月更新)
  • 研究生看文献笔记总记不好?
  • C# call store procedure with table input parameters
  • 怎么样用自己电脑做网站实用设计网站推荐
  • 【uniapp实践】主题样式配置浅色深色以及自定义
  • LangChain Model I/O 使用示例
  • 北京做网站设计公司网站开发主要参考文献
  • AI 十大论文精讲(三):RLHF 范式奠基 ——InstructGPT 如何让大模型 “听懂人话”
  • GPT-5.1 发布:更智能也更“人性化“的 AI 助手
  • std::bind 的简单使用