鸿蒙开发实战,网络请求库【axios】,鸿蒙开发实战,使用axios进行网络请求库实战

马肤

温馨提示:这篇文章已超过465天没有更新,请注意相关的内容是否还可用!

鸿蒙开发实战系列中,关于网络请求库axios的部分,介绍了如何在鸿蒙应用中使用axios进行网络请求。该部分内容详细阐述了axios库的安装、配置及其在鸿蒙开发中的实际应用,包括如何发送GET、POST等请求,以及处理响应和错误的方法。摘要字数控制在100-200字以内:,,鸿蒙开发实战系列讲解了网络请求库axios在鸿蒙应用中的使用。内容涵盖安装配置axios库,以及通过GET、POST等请求方式在鸿蒙开发中实现网络请求。还介绍了响应和错误处理的方法。

简介

[Axios] ,是一个基于 promise 的网络请求库,可以运行 node.js 和浏览器中。本库基于[Axios]原库v1.3.4版本进行适配,使其可以运行在 OpenHarmony,并沿用其现有用法和特性。

  • http 请求
  • Promise API
  • request 和 response 拦截器
  • 转换 request 和 response 的 data 数据
  • 自动转换 JSON data 数据

    鸿蒙开发实战,网络请求库【axios】,鸿蒙开发实战,使用axios进行网络请求库实战 第1张

    下载安装

    ohpm install @ohos/axios
    

    需要权限

    ohos.permission.INTERNET
    

    接口和属性列表

    接口列表

    接口参数功能
    axios(config)[config]:请求配置发送请求
    axios.create(config)[config]:请求配置创建实例
    axios.request(config)[config]:请求配置发送请求
    axios.get(url[, config])url:请求地址 [config]:请求配置发送get请求
    axios.delete(url[, config])url:请求地址 [config]:请求配置发送delete请求
    axios.post(url[, data[, config]])url:请求地址 data:发送请求体数据 [config]:请求配置发送post请求
    axios.put(url[, data[, config]])url:请求地址 data:发送请求体数据 [config]:请求配置发送put请求

    属性列表

    属性描述
    axios.defaults[‘xxx’]默认设置 。值为请求配置 [config] 中的配置项 例如 axios.defaults.headers 获取头部信息
    axios.interceptors拦截器。参考 [拦截器] 的使用

    使用示例

    使用前在demo中entry–>src–>main–>ets–>common–>Common.ets文件中改为正确的服务器地址,在entry–>src–>main–>resources–>rawfile目录下添加正确的证书,才可正常的使用demo。

    发起一个 GET 请求

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

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

      发送一个 POST 请求

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

      发起多个并发请求

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

      使用说明

      axios API

      通过向 axios 传递相关配置来创建请求
      axios(config)
      // 发送一个get请求
      axios({
        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('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('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 实例

        创建一个实例

        您可以使用自定义配置新建一个实例。

        axios.create([config])

        const instance = axios.create({
          baseURL: 'https://www.xxx.com/info',
          timeout: 1000,
          headers: {'X-Custom-Header': 'foobar'}
        });
        
        实例方法
        • axios#request(config)
        • axios#get(url[, config])
        • axios#delete(url[, config])
        • axios#post(url[, data[, config]])
        • axios#put(url[, data[, config]])

          )请求配置

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

          {
            // `url` 是用于请求的服务器 URL
            url: '/user',
            
            // `method` 是创建请求时使用的方法 支持post/get/put/delete方法,不区分大小写,默认为get方法
            method: 'get', // default
            
            // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
            // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
            baseURL: 'https://www.xxx.com/info',
            
            // `transformRequest` 允许在向服务器发送前,修改请求数据
            // 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
            // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
            // 你可以修改请求头。
            transformRequest: [function (data, headers) {
              // 对发送的 data 进行任意转换处理
              return data;
            }],
            // `transformResponse` 在传递给 then/catch 前,允许修改响应数据
            transformResponse: [function (data) {
              // 对接收的 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, ArrayBuffer
            data: {
              firstName: 'Fred'
            },
            
            // 发送请求体数据的可选语法
            // 请求方式 post
            // 只有 value 会被发送,key 则不会
            data: 'Country=Brasil&City=Belo Horizonte',
            
            // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
            // 如果请求超过 `timeout` 的时间,请求将被中断
            timeout: 1000,
            
            // `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)。
            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 port
                port: xx, // Host port
                exclusionList: [] // 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,
            }
          

          响应结构

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

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

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

          axios.get(this.getUrl)
           .then( (response:AxiosResponse)=> {
             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);
           });
          

          默认配置

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

          全局 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(this.getUrl, {
            timeout: 5000
          })
          

          拦截器

          在请求或响应被 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)=> {/*...*/});
          

          指定返回数据的类型

          responseType 指定返回数据的类型,默认无此字段。如果设置了此参数,系统将优先返回指定的类型。 选项包括: string:字符串类型; object:对象类型; array_buffer:二进制数组类型。 设置responseType后,response.data中的数据将为指定类型

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

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

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

          自定义ca证书

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

          自定义客户端证书

            axios({
              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) => {
              //
            })
          

          设置代理

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

          证书锁定

          证书锁定的用法如下:

          需要在配置文件中对证书进行相关信息的配置:配置文件路径为: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  
          

          上传下载文件

          上传文件示例
          • 上传文件需要单独导入FormData模块
          • 当前版本只支持 Stage 模型
          • 上传类型支持uri和ArrayBuffer,uri支持“internal”协议类型,仅支持"internal"协议类型,"internal://cache/"为必填字段,示例: internal://cache/path/to/file.txt
          • 请求的表单数据值为string类型
            当上传的内容为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);
            } catch (err) {
              console.info('err:' + JSON.stringify(err));
            }
            // 发送请求
            axios.post(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')
            // 发送请求
            axios.post('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) => {
              console.info("result" + JSON.stringify(res.data));
            }).catch((err: AxiosError) => {
              console.error("error:" + JSON.stringify(err));
            })
            
            下载文件示例

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

            关于filePath

            filePath:‘workspace/test.txt’:默认路径下创建workspace路径,并将文件存储在workspace路径下。

            filePath:‘test.txt’:将文件存储在默认路径下。

            filePath:‘workspace/’:默认路径下创建workspace路径,并将文件存储在workspace路径下。

            • 当前版本只支持 Stage 模型 下载文件时,如果filePath已存在该文件则下载失败,下载之前需要先删除文件。
              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));
              })
              

              错误处理

              错误处理示例代码
              axios.get('/user/12345')
                .catch((error:AxiosError)=> {
                  console.log(JSON.stringify(error.message));
                  console.log(JSON.stringify(error.code));
                  console.log(JSON.stringify(error.config));
                });
              
              错误码
              • 网络请求异常时,catch方法接收到异常,异常错误码 [请点击查看]
              • 错误常量
                名称参数类型可读可写说明
                NETWORK_MOBILEnumber使用蜂窝网络时允许下载的位标志。
                NETWORK_WIFInumber使用WLAN时允许下载的位标志。
                ERROR_CANNOT_RESUME7+number某些临时错误导致的恢复下载失败。
                ERROR_DEVICE_NOT_FOUND7+number找不到SD卡等存储设备。
                ERROR_FILE_ALREADY_EXISTS7+number要下载的文件已存在,下载会话不能覆盖现有文件。
                ERROR_FILE_ERROR7+number文件操作失败。
                ERROR_HTTP_DATA_ERROR7+numberHTTP传输失败。
                ERROR_INSUFFICIENT_SPACE7+number存储空间不足。
                ERROR_TOO_MANY_REDIRECTS7+number网络重定向过多导致的错误。
                ERROR_UNHANDLED_HTTP_CODE7+number无法识别的HTTP代码。
                ERROR_UNKNOWN7+number未知错误。
                PAUSED_QUEUED_FOR_WIFI7+number下载被暂停并等待WLAN连接,因为文件大小超过了使用蜂窝网络的会话允许的最大值。
                PAUSED_UNKNOWN7+number未知原因导致暂停下载。
                PAUSED_WAITING_FOR_NETWORK7+number由于网络问题(例如网络断开)而暂停下载。
                PAUSED_WAITING_TO_RETRY7+number发生网络错误,将重试下载会话。
                SESSION_FAILED7+number下载会话已失败,将不会重试。
                SESSION_PAUSED7+number下载会话已暂停。
                SESSION_PENDING7+number正在调度下载会话。
                SESSION_RUNNING7+number下载会话正在进行中。
                SESSION_SUCCESSFUL7+number下载会话已完成。

                鸿蒙开发知识更新在gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md前往参考。

                鸿蒙开发实战,网络请求库【axios】,鸿蒙开发实战,使用axios进行网络请求库实战 第2张

                约束与限制

                在下述版本验证通过: DevEco Studio: 4.1 Canary2(4.1.3.325), SDK: API11(4.1.0.36)

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

                FAQ

                • 服务器返回多个cookie,response.header中只能读取首个cookie。

                  由于该库底层依赖ohos.net.http模块,ohos.net.http也存在此问题,204.1.0.33 镜像版本已修复此问题。


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码