一 概述
现在鸿蒙的网络还不成熟,所以咱们需要对网络请求框架二次封装,并且避免业务方直接引用到
,预防当有比较新的成熟性价比高的框架的替换,这个过程肯定是不可避免的
1.1 第三方比如
- [axios]的js库迁移过来的
- [httpclient]通过socket,基于android中著名的 [okhttp]的代码写的
1.2 官方的
http和rcp的区别
- [@ohos.net.http]暂不会再演进或新增其他功能
- [rcp] 在接口易用性、性能、功耗方面比http网络库好,
以后主推这个,但是也不确定后续是否还会出来第三套
二 [@ohos.request (上传下载)]
如果对上传和下载高度定制的,可以使用 [@ohos.request (上传下载)],如果不想有通知显示,可以mode: request.agent.Mode.FOREGROUND就可以关闭通知栏显示
二 rcp
同一个session ,没有请求限制,经过测试没有请求限制,一个App最多能创建16个session,再创建就会报错,所以我们整个APP需要两个session即可,一个是请求接口,一个是下载上传使用。
先说坑点
- 坑1:downloadToFile 无法暂停,好像也符合设计,如果是大文件可以使用 [@ohos.request (上传下载)]mode: request.agent.Mode.FOREGROUND
- 坑2:get请求,没有直接可以传递参数的,得咱们自己拼接到url上面
二次分装 HttpHelper,暂时不写接口隔离的方式了,
-
baseUrl
-
sessionHelper 主要提供session,一般上传下载的session 不能同时进行两个,因为回调无法分开,
-
headers 咱们请求的一些公共header
-
User-Agent: 提供关于客户端软件的信息,例如浏览器类型和版本
-
Accept: 客户端可接受的内容类型 ,例如 application/json
-
Accept-Encoding: 客户端可接受的编码方式,如gzip,br
-
Content-Type: 它告诉服务 如何解析和处理请求
-
- application/json 表示请求或响应体中的数据是 JSON 格式
-
- application/x-www-form-urlencoded 用于表单提交,表示数据以键值对的形式编码
-
- multipart/form-data 用于表单上传文件时,数据以多部分的形式发送,适合上传文件和其他数据
-
-
Cookie: 用于在客户端存储会话信息的一种方式
-
Authorization:用于提供身份验证信息,通常用于 API 访问
-
Connection: 如keep-alive ,指定连接的选项,例如是否保持连接
-
export class HttpHelper {
baseUrl: string = '';
sessionHelper = new SessionHelper();
normalSession: rcp.Session = this.sessionHelper.createNormalSession();
// User-Agent: 提供关于客户端软件的信息,例如浏览器类型和版本
// Accept: 客户端可接受的内容类型 ,例如 application/json
// Accept-Encoding: 客户端可接受的编码方式,如gzip,br
// Content-Type: 它告诉服务 如何解析和处理请求
// 1. application/json 表示请求或响应体中的数据是 JSON 格式
// 2. application/x-www-form-urlencoded 用于表单提交,表示数据以键值对的形式编码
// 3. multipart/form-data 用于表单上传文件时,数据以多部分的形式发送,适合上传文件和其他数据
// Cookie: 用于在客户端存储会话信息的一种方式
// Connection: 如keep-alive ,指定连接的选项,例如是否保持连接
// Authorization:用于提供身份验证信息,通常用于 API 访问
headers: rcp.RequestHeaders = {
'authorization': 'token',
'cookie': 'cookie',
'user-agent': 'nzy手机',
'accept': 'application/json',
'content-type': 'application/x-www-form-urlencoded', // post时候使用 表单,告知服务器如何解析
// 'content-type': 'application/json',// post的时候使用body
// 'content-type': 'multipart/form-data' // multipart
'Connection': 'Keep-Alive',
'accept-encoding': 'br,gzip', // 压缩方式
};
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
}
BaseResponse
跟服务端商量好,比如errorCode=0是正常流程,其他是否需要showToast看业务需要,自己配置就好
ts
代码解读
复制代码
export interface BaseResponse<T> {
errorCode: number
errorMsg: string
data: T
}
get请求T
get请求不要传递到RequestContent ,他会跑到body里面,我们只能自己拼接到
async get<T>(path: string, params?: Record<string, RequestMapValue>): Promise<T> {
// get 就不要放到params里面了,否则跑到body里面了,直接拼接到后面
let newUrl = this.baseUrl + path
if (params) {
newUrl += '?' + Object.keys(params)
.map(k => `${k}=${params[k]}`)
.join('&')
}
let req = new rcp.Request(newUrl, 'GET', this.headers);
let response = await this.normalSession.fetch(req)
if (response.statusCode == 200) {
let responseBase: T = response.toJSON() as T
// 成功了
return responseBase
} else {
return Promise.reject({ code: response.statusCode, message: 'http非200' })
}
}
get请求BaseResponse 非0 就让他走到异常里面
这里把data内容包装成泛型,有时候需要非0的时候 需要toast errorMessage
,可以做对应的逻辑处理,使用方错误的时候有三种情况
- http code码非200
- errorCode 非 0 ,这是跟后端对的业务,是否需要toast
errorMessage
- 业务处理的时候,crash了,
async get<T>(path: string, params?: Record<string, RequestMapValue>): Promise<T> {
// get 就不要放到params里面了,否则跑到body里面了,直接拼接到后面
let newUrl = this.baseUrl + path
if (params) {
newUrl += '?' + Object.keys(params)
.map(k => `${k}=${params[k]}`)
.join('&')
}
let req = new rcp.Request(newUrl, 'GET', this.headers);
let response = await this.normalSession.fetch(req)
if (response.statusCode == 200) {
let responseBase: T = response.toJSON() as T
// 成功了
return responseBase
} else {
return Promise.reject({ netStatus: NetStatus.httpError, code: response.statusCode, message: 'http非200' })
}
}
业务调用的时候
http.getBase<HarmonyData>("/project/list/1/json", { "cid": 249 })
.then((data) => {
Logger.json(data, 'response')
// 非 0 就过去了
this.message = JSON.stringify(data, null, 2)
})
.catch((err: NetError) => {
Logger.error(err);
if (err.netStatus) {
// 证明是 http 错误
if (err.netStatus == NetStatus.businessError) {
//是否需要toast message
promptAction.showToast({ message: err.message })
}
} else {
// 代表业务有异常 ,也就是then里面代码crash了
}
})
POST 请求
post 请求分为三类,
- JSON数据,也就是body里面是JSON格式
- Form表单格式 body里是这样的password=xxx&username=xxx
- Multipart格式,一般是包括文件,比如上传头像
POST JSON
这里因为我们不知道具体会给多少层,所以用了 value是ESObject 格式
async post<T>(path: string, params?: Record<string, ESObject>): Promise<T> {
// 变更header中的 content-type 为 Body 格式
this.headers['content-type'] = 'application/json'
let req = new rcp.Request(`${this.baseUrl}${path}`, 'POST', this.headers, params);
let response = await this.normalSession.fetch(req)
if (response.statusCode == 200) {
let responseBase: T = response?.toJSON() as T
// 成功了
return responseBase
} else {
return Promise.reject({ netStatus: NetStatus.httpError, code: response.statusCode, message: 'http非200' })
}
}
使用
http.post<BaseResponse<HarmonyData>>(
"/user/login",
{
'username': 'nzyandroid',
'password': 'nzyandroid',
'content': {
'name': 'nzy',
'age': 18
}
})
.then((data) => {
Logger.json(data, 'response')
this.message = JSON.stringify(data, null, 2)
})
.catch((err: BusinessError) => {
Logger.error(err);
})
POST 表单
async postForm<T>(path: string, params?: Record<string, RequestMapValue>): Promise<T> {
// 变更header中的 content-type 为 表单格式
this.headers['content-type'] = 'application/x-www-form-urlencoded'
const form = new rcp.Form(params as rcp.FormFields)
let req = new rcp.Request(`${this.baseUrl}${path}`, 'POST', this.headers, form);
let response = await this.normalSession.fetch(req)
if (response.statusCode == 200) {
let responseBase: T = response?.toJSON() as T
// 成功了
return responseBase
} else {
return Promise.reject({ netStatus: NetStatus.httpError, code: response.statusCode, message: 'http非200' })
}
}
使用
http.postForm<BaseResponse<HarmonyData>>(
"/user/login",
{
'username': 'nzyandroid',
"password": 'nzyandroid'
})
.then((data) => {
Logger.json(data, 'response')
this.message = JSON.stringify(data, null, 2)
}).catch((err: BusinessError) => {
Logger.error(`Response err: Code is ${err.code}, message is ${err.message}`);
})
POST Multipart
async postMultipartForm<T>(path: string, params?: Record<string, RequestMapValue | MultipartFormFile>): Promise<T> {
// 变更header中的 content-type 为 表单格式
this.headers['content-type'] = 'multipart/form-data'
const form = new rcp.MultipartForm(params as rcp.MultipartFormFields)
let req = new rcp.Request(`${this.baseUrl}${path}`, 'POST', this.headers, form);
let response = await this.normalSession.fetch(req)
if (response.statusCode == 200) {
let responseBase: T = response?.toJSON() as T
// 成功了
return responseBase
} else {
return Promise.reject({ netStatus: NetStatus.httpError, code: response.statusCode, message: 'http非200' })
}
}
使用
http.postMultipartForm<Object>(
"/user/login",
{
'name': 'nzy',
'file': {
remoteFileName: 'img1.jpg',
contentOrPath: getContext(this).cacheDir + '/' + 'img1.jpg'
}
})
.then((data) => {
Logger.json(data, 'response')
this.message = JSON.stringify(data, null, 2)
})
.catch((err: BusinessError) => {
Logger.error(`Response err: Code is ${err.code}, message is ${err.message}`);
})
以上就是本篇文章所带来的鸿蒙开发中一小部分技术讲解;想要学习完整的鸿蒙全栈技术。可以在结尾找我可全部拿到!
下面是鸿蒙的完整学习路线,展示如下:
除此之外,根据这个学习鸿蒙全栈学习路线,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、鸿蒙南向开发、鸿蒙项目实战)等技术知识点。帮助大家在学习鸿蒙路上快速成长!
鸿蒙【北向应用开发+南向系统层开发】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经
为了避免大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!