HarmonyOS第九章:鸿蒙axios(@ohos/axios)

devtools/2024/10/18 12:31:56/

🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区】
🎨 上一篇文章:【HarmonyOS第八章:HTTP数据请求】
🎠 系列专栏:【HarmonyOS系列】
💖 感谢大家点赞👍收藏⭐评论✍

在这里插入图片描述

在这里插入图片描述

文章目录

  • 1. 配置环境变量
  • 2. 下载安装 @ohos/axios
  • 3. @ohos/axios 接口和属性列表
    • 3.1. 接口列表
    • 3.2. 属性列表
  • 4. 使用 @ohos/axios
    • 4.1. 发起一个 GET 请求
    • 4.2. 发送一个 POST 请求
    • 4.3. 发起多个并发请求
    • 4.4. 实际项目使用
    • 5. 使用说明
  • 5. axios 实例
    • 5.1. 创建一个实例
    • 5.2. 实例方法
    • 5.3. 请求配置
    • 5.4. 响应结构
    • 5.5. 默认配置
    • 5.6. 拦截器
    • 5.7. 指定返回数据的类型
    • 5.8. 自定义ca证书
    • 5.9. 自定义客户端证书
    • 5.10.设置代理
    • 5.11. 证书锁定
    • 5.12. 上传下载文件
    • 5.13. 错误处理
    • 5.14. 约束与限制
  • 总结

1. 配置环境变量

运行 ohpm --version 或 ohpm -V 查看 ohpm 是否可运行,如显示版本号则跳过配置环境变量的步骤,如果报以下错误,则按当前步骤执行:

在这里插入图片描述
报错原因:未配置 ohpm 环境变量:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 下载安装 @ohos/axios

打开鸿蒙第三方库,找到 @ohos/axios

在这里插入图片描述
根据文档安装即可。

ohpm install @ohos/axios

在 oh-package.json5 文件查看包是否安装成功:

在这里插入图片描述

3. @ohos/axios 接口和属性列表

3.1. 接口列表

在这里插入图片描述

3.2. 属性列表

在这里插入图片描述

4. 使用 @ohos/axios

4.1. 发起一个 GET 请求

axios支持泛型参数,由于ArkTS不再支持any类型,需指定参数的具体类型。 如:axios.get<T = any, R = AxiosResponse<T>, D = any>(url)

  • T: 是响应数据类型。当发送一个 POST 请求时,客户端可能会收到一个 JSON 对象。T 就是这个 JSON 对象的类型。默认情况下,Tany,这意味着可以接收任何类型的数据。
  • R: 是响应体的类型。当服务器返回一个响应时,响应体通常是一个 JSON 对象。R 就是这个 JSON 对象的类型。默认情况下,RAxiosResponse<T>,这意味着响应体是一个 AxiosResponse 对象,它的 data 属性是 T 类型的
  • D: 是请求参数的类型。当发送一个 GET 请求时,可能会在 URL 中添加一些查询参数。D 就是这些查询参数的类型。参数为空情况下,Dnull 类型。
import axios from '@ohos/axios'
interface userInfo{id: numbername: string,phone: number
}// 向给定ID的用户发起请求
axios.get<userInfo, AxiosResponse<userInfo>, null>('/user?ID=12345')
.then((response: AxiosResponse<userInfo>)=> {// 处理成功情况console.info("id" + response.data.id)console.info(JSON.stringify(response));
})
.catch((error: AxiosError)=> {// 处理错误情况console.info(JSON.stringify(error));
})
.then(()=> {// 总是会执行
});// 上述请求也可以按以下方式完成(可选)
axios.get<userInfo, AxiosResponse<userInfo>, null>('/user', {params: {ID: 12345}
})
.then((response:AxiosResponse<userInfo>) => {console.info("id" + response.data.id)console.info(JSON.stringify(response));
})
.catch((error:AxiosError) => {console.info(JSON.stringify(error));
})
.then(() => {// 总是会执行
});// 支持async/await用法
async function getUser() {try {const response:AxiosResponse = await axios.get<string, AxiosResponse<string>, null>(this.getUrl);console.log(JSON.stringify(response));} catch (error) {console.error(JSON.stringify(error));}
}

4.2. 发送一个 POST 请求

interface user {firstName: string,lastName: string
}axios.post<string, AxiosResponse<string>, user>('/user', {firstName: 'Fred',lastName: 'Flintstone'}).then((response: AxiosResponse<string>) => {console.info(JSON.stringify(response));}).catch((error) => {console.info(JSON.stringify(error));
});

4.3. 发起多个并发请求

const getUserAccount = ():Promise<AxiosResponse> => {return axios.get<string, AxiosResponse<string>, null>('/user/12345');}const getUserPermissions = ():Promise<AxiosResponse> => {return axios.get<string, AxiosResponse<string>, null>('/user/12345/permissions');}Promise.all<AxiosResponse>([getUserAccount(), getUserPermissions()]).then((results:AxiosResponse[]) => {const acct = results[0].data as string;const perm = results[1].data as string;});

更多配置请查看@ohos/axios官方文档。

4.4. 实际项目使用

在这里插入图片描述

  • 导出 axios
  • 使用 axios 上的方法
  • 配置类型规则
import axios, { AxiosResponse, AxiosError } from "@ohos/axios"interface ICarousels {carouselUrl: string;redirectUrl: string;
}
interface IData {carousels: ICarousels[];
}
interface Data{data: IData;
}
@Entry
@Component
struct Index {getData() {axios.get<Data, AxiosResponse<Data>, null>("http://backend-api-01.newbee.ltd/api/v1/index-infos").then((response: AxiosResponse<Data>) => {console.info(JSON.stringify(response.data));}).catch((error:AxiosError) => {console.error(JSON.stringify(error));})}build() {Column(){Button("获取数据").onClick(() => {this.getData();})}.width("100%").height("100%")}
}

5. 使用说明

axios API
通过向 axios 传递相关配置来创建请求
axios(config)

// 发送一个get请求
axios<string, AxiosResponse<string>, null>({method: "get",url: 'https://www.xxx.com/info'
}).then((res: AxiosResponse) => {console.info('result:' + JSON.stringify(res.data));
}).catch((error: AxiosError) => {console.error(error.message);
})
axios(url[, config])
// 发送一个get请求(默认请求方式)
axios.get<string, AxiosResponse<string>, null>('https://www.xxx.com/info', { params: { key: "value" } })
.then((response: AxiosResponse) => {console.info("result:" + JSON.stringify(response.data));
})
.catch((error: AxiosError) => {console.error("result:" + error.message);
});

请求方法的 别名方式 来创建请求
为方便起见,为所有支持的请求方法提供了别名。

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])

注意: 在使用别名方法时, url、method、data 这些属性都不必在配置中指定。

// 发送get请求
axios.get<string, AxiosResponse<string>, null>('https://www.xxx.com/info', { params: { key: "value" } })
.then((response: AxiosResponse) => {console.info("result:" + JSON.stringify(response.data));
})
.catch((error: AxiosError) => {console.error("result:" + error.message);
});

5. axios 实例

5.1. 创建一个实例

您可以使用自定义配置新建一个实例。
axios.create([config])

const instance = axios.create({baseURL: 'https://www.xxx.com/info',timeout: 1000,headers: {'X-Custom-Header': 'foobar'}
});

5.2. 实例方法

  • axios#request(config)
  • axios#get(url[, config])
  • axios#delete(url[, config])
  • axios#post(url[, data[, config]])
  • axios#put(url[, data[, config]])

5.3. 请求配置

这些是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method,请求将默认使用 get 方法。

{// `url` 是用于请求的服务器 URLurl: '/user',// `method` 是创建请求时使用的方法 支持post/get/put/delete方法,不区分大小写,默认为get方法method: 'get', // default// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URLbaseURL: 'https://www.xxx.com/info',// `transformRequest` 允许在向服务器发送前,修改请求数据// 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream// 你可以修改请求头。transformRequest: [(data: ESObject, headers: AxiosRequestHeaders) => {// 对发送的 data 进行任意转换处理return data;}],// `transformResponse` 在传递给 then/catch 前,允许修改响应数据transformResponse: [ (data: ESObject, headers: AxiosResponseHeaders, status?: number)=> {// 对接收的 data 进行任意转换处理return data;}],// `headers` 是即将被发送的自定义请求头headers: {'Content-Type': 'application/json'},// `params` 是即将与请求一起发送的 URL 参数// 必须是一个无格式对象(plain object),其他对象如 URLSearchParams ,必须使用 paramsSerializer 进行序列化params: {ID: 12345},// `paramsSerializer` 是一个负责 `params` 序列化的函数paramsSerializer: function(params) {return params},// `data` 是作为请求主体被发送的数据// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'// 在没有设置 `transformRequest` 时,必须是以下类型之一,其他类型使用 transformRequest 转换处理// - string, plain object, ArrayBufferdata: {firstName: 'Fred'},// 发送请求体数据的可选语法// 请求方式 post// 只有 value 会被发送,key 则不会data: 'Country=Brasil&City=Belo Horizonte',// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)// 如果请求超过 `timeout` 的时间,请求将被中断timeout: 1000,// `readTimeout` 指定请求超时的毫秒数(0 表示无超时时间)// 如果请求超过 `readTimeout` 的时间,请求将被中断readTimeout: 1000,// `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)// 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断connectTimeout: 60000,// `maxBodyLength`,指定网络请求内容的最大字节数(-1 表示无最大限制)// 如果请求内容的字节数超过 `maxBodyLength`,请求将被中断并抛出异常maxBodyLength: 5*1024*1024,// `maxContentLength`,指定HTTP响应的最大字节数(-1 表示放开axios层限制),默认值为5*1024*1024,以字节为单位。最大值为100*1024*1024,以字节为单位// 如果响应的最大字节数超过 `maxContentLength`,请求将被中断并抛出异常maxContentLength: 5*1024*1024,// `adapter` 允许自定义处理请求,这使测试更加容易。// 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。adapter: function (config) {/* ... */},// 如果设置了此参数,系统将使用用户指定路径的CA证书,(开发者需保证该路径下CA证书的可访问性),否则将使用系统预设CA证书,系统预设CA证书位置:/etc/ssl/certs/cacert.pem。证书路径为沙箱映射路径(开发者可通过Global.getContext().filesDir获取应用沙箱路径)。caPath: '',// 客户端证书的clientCert字段,包括4个属性:// 客户端证书(cert)、客户端证书类型(certType)、证书私钥(key)和密码短语(keyPasswd)。certPath和keyPath为证书沙箱映射路径clientCert:{certPath: '',  // 客户端证书路径certType: '',  // 客户端证书类型,包括pem、der、p12三种keyPath: '',   // 证书私钥路径keyPasswd: ''  // 密码短语}// 优先级,范围[1,1000],默认是1,值越大,优先级越高;priority: 1,//  `responseType` 指定返回数据的类型,默认无此字段。如果设置了此参数,系统将优先返回指定的类型。// 选项包括: string:字符串类型; object:对象类型; array_buffer:二进制数组类型。responseType: 'string', //  `proxy`// 是否使用HTTP代理,默认为false,不使用代理。// 当proxy为AxiosProxyConfig类型时,使用指定网络代理。proxy: {host: 'xx', // Host portport: xx, // Host portexclusionList: [] // Do not use a blocking list for proxy servers}// `onUploadProgress` 允许为上传处理进度事件onUploadProgress: function (progressEvent) {// 对原生进度事件的处理},// `onDownloadProgress` 允许为下载处理进度事件,下载文件必须设置该事件onDownloadProgress: function (progressEvent) {// 对原生进度事件的处理},// 基于应用程序的上下文,只适用于上传/下载请求context: context,// 下载路径。此参数,只适用于下载请求,// Stage模型下使用AbilityContext 类获取文件路径,比如:'${getContext(this).cacheDir}/test.txt’并将文件存储在此路径下filePath: context,}

5.4. 响应结构

一个请求的响应包含以下信息。

{// `data` 由服务器提供的响应data: {},// `status` 来自服务器响应的 HTTP 状态码status: 200,// `statusText` 来自服务器响应的 HTTP 状态信息statusText: 'OK',// `headers` 是服务器响应头// 所有的 header 名称都是小写,而且可以使用方括号语法访问// 例如: `response.headers['content-type']`headers: {},// `config` 是 `axios` 请求的配置信息config: {},// `request` 是生成此响应的请求request: {}// `performanceTiming` 计算HTTP请求的各个阶段所花费的时间performanceTiming: http.PerformanceTiming
}

当使用 then 时,您将接收如下响应:

axios.get<string, AxiosResponse<string>, null>(this.getUrl).then( (response:AxiosResponse<string>)=> {console.log("result data: " + response.data);console.log("result status: " + response.status);console.log("result statusText: " + response.statusText);console.log("result headers: " + response.headers);console.log("result config: " + response.config);});

5.5. 默认配置

您可以指定默认配置,它将作用于每个请求。

全局 axios 默认值

axios.defaults.baseURL = 'https://www.xxx.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

自定义实例默认值

// 创建实例时配置默认值
const instance = axios.create({baseURL: 'https://www.xxx.com'
});// 创建实例后修改默认值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;

配置的优先级 配置将会按优先级进行合并。它的顺序是:在lib/defaults.js中找到的库默认值,然后是实例的 defaults 属性,最后是请求的 config 参数。后面的优先级要高于前面的。下面有一个例子。

// 使用库提供的默认配置创建实例
// 此时超时配置的默认值是 `0`
const instance = axios.create();// 重写库的超时默认值
// 现在,所有使用此实例的请求都将等待2.5秒,然后才会超时
instance.defaults.timeout = 2500;// 重写此请求的超时时间,因为该请求需要很长时间
instance.get<string, AxiosResponse<string>, null>(this.getUrl, {timeout: 5000
})

5.6. 拦截器

在请求或响应被 then 或 catch 处理前拦截它们。

// 添加请求拦截器
axios.interceptors.request.use((config:InternalAxiosRequestConfig) => {// 对请求数据做点什么return config;
}, (error:AxiosError) => {// 对请求错误做些什么return Promise.reject(error);
});// 添加响应拦截器
axios.interceptors.response.use((response:AxiosResponse)=> {// 对响应数据做点什么return response;
}, (error:AxiosError)=> {// 对响应错误做点什么return Promise.reject(error);
});

移除拦截器

const myInterceptor = axios.interceptors.request.use((response: AxiosResponse)=> {/*...*/});
axios.interceptors.request.eject(myInterceptor);

可以给自定义的 axios 实例添加拦截器

const instance = axios.create();
instance.interceptors.request.use((config:InternalAxiosRequestConfig)=> {/*...*/});

5.7. 指定返回数据的类型

  • responseType 指定返回数据的类型,默认无此字段。
  • 如果设置了此参数,系统将优先返回指定的类型。
  • 选项包括:
    • string:字符串类型;
    • object:对象类型;
    • array_buffer:二进制数组类型。
  • 设置responseType后,response.data中的数据将为指定类型
 axios<string, AxiosResponse<string>, null>({url: 'https://www.xxx.com/info',method: 'get',responseType: 'array_buffer', }).then((res: AxiosResponse) => {// 处理请求成功的逻辑})

注意:也可以通过重写transformResponse方法,修改返回数据;

 axios<string, AxiosResponse<string>, null>({url: 'https://www.xxx.com/info',method: 'get',responseType: 'array_buffer', transformResponse:(data)=>{return data}}).then((res: AxiosResponse) => {// 处理请求成功的逻辑})

5.8. 自定义ca证书

  axios<infoModel, AxiosResponse<infoModel>, null>({url: 'https://www.xxx.com/xx',method: 'get',caPath: '', //ca证书路径}).then((res: AxiosResponse) => {// }).catch((err: AxiosError) => {//})

5.9. 自定义客户端证书

  axios<infoModel, AxiosResponse<infoModel>, null>({url: 'https://www.xxx.com/xx',method: 'get',caPath: '', //ca证书路径clientCert: {certPath: '', //客户端证书路径certType: 'p12', // 客户端证书类型,包括pem、der、p12三种keyPath: '', //客户端私钥路径keyPasswd: '' // 密码}}).then((res: AxiosResponse) => {// }).catch((err: AxiosError) => {//})

5.10.设置代理

    axios<string, AxiosResponse<string>, null>({url: 'xxx',method: 'get',proxy:{host: 'xxx',port: xx,exclusionList: []}}).then((res: AxiosResponse) => {// }).catch((err: AxiosError) => {//})

5.11. 证书锁定

证书锁定的用法如下:

需要在配置文件中对证书进行相关信息的配置:配置文件路径为:
entry/src/main/resources/base/profile/network_config.json

配置文件:network_config

{"network-security-config": {"domain-config": [{"domains": [{"include-subdomains": true,"name": "x.x.x.x"  // ip地址或域名}],"pin-set": {"expiration": "2024-8-6", //证书锁定的有效期"pin": [{"digest-algorithm": "sha256", //消息摘要的哈希算法,支持格式是sha256 "digest": "WAFcHG6pAINrztx343ccddfzLOdfoDS9pPgMv2XHk=" //消息摘要}]}}]}
}

digest字段消息摘要获取

使用openssl从服务器获取证书,并提取出消息摘要

openssl s_client -connect host:port 2>&1 < /dev/null \| sed -n '/-----BEGIN/,/-----END/p' \| openssl x509 -noout -pubkey \| openssl pkey -pubin -outform der \| openssl dgst -sha256 -binary \| openssl enc -base64

5.12. 上传下载文件

上传文件示例

  • 上传文件需要单独导入FormData模块
  • 当前版本只支持 Stage 模型
  • 上传类型支持uriArrayBufferuri支持“internal”协议类型和沙箱路径。"internal://cache/"为必填字段,示例: internal://cache/path/to/file.txt;沙箱路径示例:cacheDir + '/hello.txt'
  • 请求的表单数据值为string类型
  • 支持设置多部分表单数据的数据名称和数据类型
  • 上传参数context:当uri为沙箱路径,无需传参context;若uri“internal”协议类型,必须传参context
  • v2.2.1-rc.1及以下版本上传必须传context参数,v2.2.1-rc.1以上版本上传参数可去掉context参数

当上传的内容为ArrayBuffer时,用法如下

import axios from '@ohos/axios'
import { FormData } from '@ohos/axios'
import fs from '@ohos.file.fs';// ArrayBuffer
let formData = new FormData()
let cacheDir = getContext(this).cacheDir
try {// 写入let path = cacheDir + '/hello.txt';let file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)fs.writeSync(file.fd, "hello, world"); // 以同步方法将数据写入文件fs.fsyncSync(file.fd); // 以同步方法同步文件数据。fs.closeSync(file.fd);// 读取let file2 = fs.openSync(path, 0o2);let stat = fs.lstatSync(path);let buf2 = new ArrayBuffer(stat.size);fs.readSync(file2.fd, buf2); // 以同步方法从流文件读取数据。fs.fsyncSync(file2.fd);fs.closeSync(file2.fd);formData.append('file', buf2);// formData.append('file', buf2, { filename: 'text.txt', type: 'text/plain'}); 设置多部分表单数据的数据名称和数据类型类型
} catch (err) {console.info('err:' + JSON.stringify(err));
}
// 发送请求
axios.post<string, AxiosResponse<string>, FormData>(this.uploadUrl, formData, {headers: { 'Content-Type': 'multipart/form-data' },context: getContext(this),onUploadProgress: (progressEvent: AxiosProgressEvent): void => {console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');
},
}).then((res: AxiosResponse) => {console.info("result" + JSON.stringify(res.data));
}).catch((error: AxiosError) => {console.error("error:" + JSON.stringify(error));
})
当上传的uri时,用法如下
import axios from '@ohos/axios'
import { FormData } from '@ohos/axios'let formData = new FormData()
formData.append('file', 'internal://cache/blue.jpg')
// formData.append('file', cacheDir + '/hello.txt'); uri支持传入沙箱路径// 发送请求
axios.post<string, AxiosResponse<string>, FormData>('https://www.xxx.com/upload', formData, {headers: { 'Content-Type': 'multipart/form-data' },context: getContext(this),onUploadProgress: (progressEvent: AxiosProgressEvent): void => {console.info(progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%');},
}).then((res: AxiosResponse<string>) => {console.info("result" + JSON.stringify(res.data));
}).catch((err: AxiosError) => {console.error("error:" + JSON.stringify(err));
})

FormData介绍
FormData对象是axios内部自定义的类型,用以将数据编译成键值对,以便用来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据 (keyed data)。

import { FormData } from '@ohos/axios'let formData: FormData = new FormData();formData.append("username", "Groucho");
formData.append("accountnum", "123456");
formData.append("accountnum", "123456");
formData.append("file", "internal://cache/xx/file.txt", { filename: "text.txt", type: "text/plain"}); 

上面的示例创建了一个 FormData 实例,包含"username"、"accountnum"字段。使用 append() 方法时,可以通过第三个可选参数设置多部分表单数据的数据名称和数据类型

下载文件示例
设置下载路径filePath(默认在’internal://cache/'路径下)。

  • 当前版本只支持 Stage 模型,使用AbilityContext 类获取文件路径。
  • 下载文件时,如果filePath已存在该文件则下载失败,下载之前需要先删除文件
  • 不支持自动创建目录,若下载路径中的目录不存在,则下载失败
    - v2.2.1-rc.1及以下版本下载必须传context参数,v2.2.1-rc.1以上版本下载参数可去掉context参数
let filePath = getContext(this).cacheDir + '/blue.jpg'
// 下载。如果文件已存在,则先删除文件。
try {fs.accessSync(filePath);fs.unlinkSync(filePath);
} catch(err) {}axios({url: 'https://www.xxx.com/blue.jpg',method: 'get',// context: getContext(this),filePath: filePath ,onDownloadProgress: (progressEvent: AxiosProgressEvent): void => {console.info("progress: " + progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) : 0)}
}).then((res)=>{console.info("result: " + JSON.stringify(res.data));
}).catch((error)=>{console.error("error:" + JSON.stringify(error));
})

5.13. 错误处理

错误处理示例代码

axios.get<string, AxiosResponse<string>, null>('/user/12345').catch((error:AxiosError)=> {console.log(JSON.stringify(error.message));console.log(JSON.stringify(error.code));console.log(JSON.stringify(error.config));});

错误码

在这里插入图片描述

5.14. 约束与限制

在下述版本验证通过: DevEco Studio: NEXT Developer Beta1(5.0.3.122), SDK: API12(5.0.0.18)

注意:除双向证书验证及证书锁定功能必须使用API11外,其余功能支持API10

总结

@ohos/axios 为 HarmonyOS 开发者提供了一个强大且易用的 HTTP 客户端库,支持多种文件处理方式和进度监控功能。通过本文的介绍,开发者可以更好地理解和应用 @ohos/axios 进行高效的网络请求和文件管理。


http://www.ppmy.cn/devtools/118139.html

相关文章

408算法题leetcode--第16天

144. 二叉树的前序遍历 144. 二叉树的前序遍历思路&#xff1a;递归和非递归时间&#xff1a;O(n)&#xff1b;空间&#xff1a;O(n) /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(…

C语言中定义指针,函数指针这种类似的变量(个人纪录)

C语言中定义各种变量 //1、定义一个指针 int *p; //定义一个数组 int nums[3] {1, 2, 3}; //2、定义一个指针数组 // 顾名思义 是一个数组,数组里面都是存的指针变量。 int *ptrArray[10]; // 这是一个指针数组&#xff0c;包含10个指向整数的指针 …

测试用例的举例

1. 基于测试公式设计测试用例 通过功能&#xff0c;性能&#xff0c;安全性&#xff0c;界面&#xff0c;安全性&#xff0c;易用&#xff0c;兼容对于一个水杯进行测试用例的设计&#xff1b; 对于一个软件的测试用例设计&#xff1a; 功能&#xff1a;软件本质上能够用来干什…

【unity进阶知识1】最详细的单例模式的设计和应用,继承和不继承MonoBehaviour的单例模式,及泛型单例基类的编写

文章目录 前言一、不使用单例二、普通单例模式1、单例模式介绍实现步骤&#xff1a;单例模式分为饿汉式和懒汉式两种。 2、不继承MonoBehaviour的单例模式2.1、基本实现2.2、防止外部实例化对象2.3、最终代码 3、继承MonoBehaviour的单例模式3.1、基本实现3.2、自动创建和挂载单…

废品回收小程序:回收更加便捷!

在日常生活中&#xff0c;废品回收已经成为了一种常见事&#xff0c;随着电商的快速发展&#xff0c;居民难免会产生大量的废纸盒等可回收物&#xff0c;以及在日常生活中产生的其他回收物&#xff0c; 目前&#xff0c;废品回收市场也发生了改革&#xff0c;传统的“叫卖”方…

【嵌入式开发】有关16head(16接口点击器)相关的资料

16接口点击头产品运用ESP8266 ESP8266是一款功能强大的低成本WiFi芯片&#xff0c;它支持多种网络协议&#xff0c;能够实现各种网络通信功能。 点击学习详细内容 之前讲解的点击器是用串口连接后&#xff0c;使用触控头来控制的方法 后续会在CSDN上讲解该板子用http请求控制…

研究生如何利用 ChatGPT 帮助开展日常科研工作?

ChatGPT科研 一、 如何精读论文“三步提问法”1.为什么要做这个研究&#xff1f;这个研究是否值得我们做&#xff1f;2.他们怎么做这个研究3.他们发现了什么&#xff1f; 二、如何利用ChatGPT快速精读论文&#xff1f;首先&#xff0c;“三步走之第一步”--为什么要做这个研究&…

深度解读 2024 Gartner DevOps 魔力象限

上周 Gartner 刚发布了 2024 年度的 DevOps 魔力象限。我们也第一时间来深度解读一下这份行业里最权威的报告。 和2023年对比 23 年入围 14 家厂商&#xff0c;24 年入围 11 家。4 家厂商从报告中消失&#xff0c;分别是 Bitrise, Codefresh, Google Cloud Platform (GCP), VM…