# httpclient **Repository Path**: prashantpatil/httpclient ## Basic Information - **Project Name**: httpclient - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 86 - **Created**: 2022-07-28 - **Last Updated**: 2022-07-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## httpclient ## 简介 HTTP是现代应用程序通过网络交换数据和媒体的的主要方式。httpclient是OpenHarmony 里一个高效执行的HTTP客户端,使用它可使您的内容加载更快,并节省您的流量。httpclient以人们耳熟能详的OKHTTP为基础,整合android-async-http,AutobahnAndroid,OkGo等库的功能特性,致力于在OpenHarmony 打造一款高效易用,功能全面的网络请求库。当前版本的httpclient依托系统提供的网络请求能力和上传下载能力,在此基础上进行拓展开发,已经实现的功能特性如下所示: 1.支持全局配置调试开关,超时时间,公共请求头和请求参数等,支持链式调用。 2.可以搭配[okio](https://gitee.com/openharmony-tpc/okio)库优化数据传输,搭配[retrofit](https://gitee.com/openharmony-tpc/retrofit)使用注解定义接口,让您的代码看起来更简洁美观。 3.自定义任务调度器维护任务队列处理同步/异步请求,支持tag取消请求。 4.支持设置自定义拦截器。 5.支持重定向。 6.支持客户端解压缩。 7.支持文件上传下载。 8.支持cookie管理。 ## 下载安装 ```javascript npm install @ohos/httpclient --save ``` OpenHarmony npm环境配置等更多内容,请参考[如何安装OpenHarmony npm包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_npm_usage.md) ## 使用说明 ``` import httpclient from '@ohos/httpclient'; ``` 获取HttpClient对象并配置超时时间 ```javascript this.client =new httpclient.HttpClient.Builder() .setConnectTimeout(10000) .setReadTimeout(10000) .setWriteTimeout(10000) .build(); var status :string= '' // 响应码 var content:string= '' // 响应内容 ``` ### GET请求方法示例 ```javascript // 配置请求参数 let request = new httpclient.Request.Builder() .get("https://postman-echo.com/get?foo1=bar1&foo2=bar2") .addHeader("Content-Type", "application/json") .params("testKey1", "testValue1") .params("testKey2", "testValue2") .build(); // 发起请求 this.client.newCall(request).enqueue((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }, (error)=> { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); }) ``` ### POST请求方法示例 ```javascript let request = new httpclient.Request.Builder() .url("https://postman-echo.com/post") .post(httpclient.RequestBody.create("test123")) .addHeader("Content-Type", "application/json") .build(); this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error)=> { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); }) ``` ### POST请求方法带两个参数示例 ```javascript let request = new httpclient.Request.Builder() .url("https://postman-echo.com/post") .post(httpclient.RequestBody.create({ a: 'a1', b: 'b1' }, new httpclient.Mime.Builder() .contentType('application/json', 'charset', 'utf8').build().getMime())) .build(); // 发起同步请求 this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error)=> { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### POST请求方法使用FormEncoder示例 ```javascript let formEncoder = new httpclient.FormEncoder.Builder() .add('key1', 'value1') .add('key2', 'value2') .build(); let feBody = formEncoder.createRequestBody(); var request = new httpclient.Request.Builder() .url("https://postman-echo.com/post") .post(feBody) .build(); this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error)=> { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### 异步上传示例 需要在AbilityStage或者Ability 里面获取全局使用的context对象 ```javascript export default class MainAbility extends Ability { onCreate(want, launchParam) { console.log("[Demo] MainAbility onCreate") globalThis.abilityWant = want; } onWindowStageCreate(windowStage) { // Main window is created, set main page for this ability console.log("[Demo] MainAbility onWindowStageCreate") // 定义全局使用的Context globalThis.abilityContext = this.context; // 定义全局使用的缓存路径 /data/storage/el2/base/haps/entry/cache globalThis.cacheDir = this.context.cacheDir // 定义全局使用的缓存路径 /data/storage/el2/base/haps/entry/files globalThis.filesDir = this.context.filesDir windowStage.setUIContent(this.context, "pages/index", null) } }; ``` 获取上传文件的路径 并生成上传文件(此步骤可以省略 上传文件也可通过命令导入设备) ,同时处理上传文件路径 ```javascript const ctx = this Log.showInfo(" cacheDir " + globalThis.cacheDir) let filePath = globalThis.cacheDir + this.fileName; Log.showInfo(" filePath " + filePath) let fd = fileIO.openSync(filePath, 0o102, 0o666) fileIO.ftruncateSync(fd) fileIO.writeSync(fd, "test httpclient") fileIO.fsyncSync(fd) fileIO.closeSync(fd) Log.showInfo(" writeSync "); Log.showInfo( "create file success ") // 由于文件上传目前仅支持“dataability”和“internal”两种协议类型, // 但“internal”仅支持临时目录,示例 internal://cache/path/to/file.txt // 所以需要将拿到的文件路径转化为internal格式的路径 filePath = filePath.replace(globalThis.cacheDir, "internal://cache"); ``` 开始上传 ```javascript //生成文件上传对象并包装参数 let fileUploadBuilder = new httpclient.FileUpload.Builder() .addFile(filePath) .addData("name2", "value2") .build(); let fileObject = fileUploadBuilder.getFile(); let dataObject = fileUploadBuilder.getData(); Log.showInfo( "fileObject: "+JSON.stringify(fileObject)); Log.showInfo( "dataObject: "+JSON.stringify(dataObject)); Log.showInfo('cacheDir = ' + globalThis.abilityContext.cacheDir); Log.showInfo('filesDir = ' + globalThis.abilityContext.filesDir); Log.showInfo("type of :"+ typeof globalThis.abilityContext) // 生成上传参数 let request = new httpclient.Request.Builder() .url(this.fileServer) .addFileParams(fileObject, dataObject) .setAbilityContext(globalThis.abilityContext) .build(); this.client.newCall(request).execute().then((data) => { // 上传进度回调监听 data.on('progress', (uploadedSize, totalSize) => { Log.showInfo('progress--->uploadedSize: ' + uploadedSize + ' ,totalSize--->' + totalSize); if (uploadedSize == totalSize){ Log.showInfo("upload success") } }) // 上传完毕回调监听 data.on('headerReceive', (headers) => { Log.showInfo( 'progress--->uploadSize: ' + JSON.stringify(headers)); }) }).catch((error)=> { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### PUT请求示例 ```javascript let request = new httpclient.Request.Builder() .url("https://postman-echo.com/put") .put(httpclient.RequestBody.create({ a: 'a1', b: 'b1' }, new httpclient.Mime.Builder() .contentType('application/json', 'charset', 'utf8').build())) .build(); this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error) => { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### DELETE请求示例 ```javascript let request = new httpclient.Request.Builder() .url("https://reqres.in/api/users/2") .delete() .build(); this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error) => { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### 文件下载请求示例 ```javascript try { this.status = ""; let fPath = globalThis.abilityContext.filesDir + "/sampleEnqueue.jpg"; // request可以不设置下载路径fPath,如果不设置下载路径fPath,下载的文件默认缓存在cache文件夹 var request = new httpclient.Request.Builder() .download("https://imgkub.com/images/2022/03/09/pexels-francesco-ungaro- 15250411.jpg", fPath) .setAbilityContext(globalThis.abilityContext) .build(); // 发起请求 this.client.newCall(request).enqueue((downloadTask) => { // 设置下载完成监听 downloadTask.on('complete', () => { Log.showInfo(" download complete"); this.content = "Download Task Completed"; }); // 设置下载进度监听 downloadTask.on("progress", ( receivedSize, totalSize)=>{ Log.showInfo(" downloadSize : "+receivedSize+" totalSize : "+totalSize); this.content = ""+(receivedSize/totalSize)*100; }); }, (error)=> { this.status = ""; this.content = error.data; Log.showError("onError -> Error : " + this.content); }); } catch (err) { Log.showError(" execution failed - errorMsg : "+err); } ``` ### cookie使用示例 初始化cookie管理相关的CookieJar,CookieManager,CookieStore ```javascript cookieJar = new httpclient.CookieJar(); // 初始化cookie存取校验工具 cookieManager = new httpclient.CookieManager(); // 初始化cookie策略管理工具 store = new httpclient.CookieStore(globalThis.cacheDir); // 初始化cookie存储管理工具 ``` 设置cookie策略为ACCEPT_ALL或者ACCEPT_ORIGINAL_SERVER ```javascript this.cookieManager.setCookiePolicy(httpclient.CookiePolicy.ACCEPT_ALL); this.cookieJar.setCookieStore(this.store); // this.cookieManager.setCookiePolicy(httpclient.CookiePolicy.ACCEPT_ORIGINAL_SERVER); ``` 配置cookie管理并开始请求 ```javascript var self = this; //设置请求参数,配置cookie管理工具 let request1 = new httpclient.Request.Builder() .get() .url(this.yourServer) .tag("tag_cookie1") .setCookieJar(this.cookieJar) .setAbilityContext(globalThis.abilityContext) .setCookieManager(this.cookieManager) .addHeader("Content-Type", "application/json") .build(); self.client.newCall(request1).enqueue((result) => { if (result.response) { this.status = "" + result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete cookie-> Status : " + this.status); Log.showInfo("onComplete cookie-> Content : " + JSON.stringify(this.content)); }, (error) => { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ### 拦截器使用示例 ```javascript // 通过addInterceptor添加拦截器,可以添加单个或者两个,允许为空。第一个是请求拦截器,第二个是响应拦截器 // addInterceptor允许调用多次,添加多个拦截器,拦截器的调用顺序根据添加顺序来决定 let request = new httpclient.Request.Builder() .url('https://postman-echo.com/post') .post() .body(httpclient.RequestBody.create('test123')) .setDefaultConfig(defaultConfigJSON) .addInterceptor((req) => { var route = new httpclient.Route(this.info); // Now we have got the interceptor, now we can connect to // IPAddress one after the other if previous one fails Log.showInfo("onDNSRequest and route" + route); return req; }, (res) => { return res; }) .build(); this.client.newCall(request).execute().then((result) => { if (result.response) { this.status = ""+result.response.responseCode; } if (result.response.result) { this.content = result.response.result; } else { this.content = JSON.stringify(result.response); } Log.showInfo("onComplete -> Status : " + this.status); Log.showInfo("onComplete -> Content : " + JSON.stringify(this.content)); }).catch((error) => { this.status = ""; this.content = error.data; Log.showInfo("onError -> Error : " + this.content); }); ``` ## 接口说明 ### RequestBody | 接口名 | 参数 | 返回值 | 说明 | | ------ | ---------------------------------------------- | ----------- | ------------------- | | create | content : String/JSON Object of Key:Value pair | RequestBody | 创建RequestBody对象 | ### RequestBuilder | 接口名 | 参数 | 返回值 | 说明 | | --------------- | ------------------------ | -------------- | ------------------------ | | buildAndExecute | 无 | void | 构建并执行RequestBuilder | | newCall | 无 | void | 执行请求 | | header | name:String,value:String | RequestBuilder | 传入key、value构建请求头 | | connectTimeout | timeout:Long | RequestBuilder | 设置连接超时时间 | | url | value:String | RequestBuilder | 设置请求url | | GET | 无 | RequestBuilder | 构建GET请求方法 | | PUT | body:RequestBody | RequestBuilder | 构建PUT请求方法 | | DELETE | 无 | RequestBuilder | 构建DELETE请求方法 | | POST | 无 | RequestBuilder | 构建POST请求方法 | | UPLOAD | files:Array, data:Array | RequestBuilder | 构建UPLOAD请求方法 | | CONNECT | 无 | RequestBuilder | 构建CONNECT请求方法 | ### MimeBuilder | 接口名 | 参数 | 返回值 | 说明 | | ----------- | ------------ | ------ | ----------------------------- | | contentType | value:String | void | 添加MimeBuilder contentType。 | ### FormEncodingBuilder | 接口名 | 参数 | 返回值 | 说明 | | ------ | ------------------------ | ------ | -------------------- | | add | name:String,value:String | void | 以键值对形式添加参数 | | build | 无 | void | 获取RequestBody对象 | ### FileUploadBuilder | 接口名 | 参数 | 返回值 | 说明 | | --------- | ------------------------ | ------ | --------------------------- | | addFile | furi : String | void | 添加文件URI到参数里用于上传 | | addData | name:String,value:String | void | 以键值对形式添加请求数据 | | buildFile | 无 | void | 生成用于上传的文件对象 | | buildData | 无 | void | 构建用于上传的数据 | ## 兼容性 支持OpenHarmony API version 8 及以上版本 ## 目录结构 ```javascript |---- httpclient | |---- entry # 示例代码文件夹 | |---- httpclient # httpclient 库文件夹 | |---- index.ets # httpclient对外接口 | |---- README.MD # 安装使用方法 ``` ## 贡献代码 使用过程中发现任何问题都可以提[Issue](https://gitee.com/openharmony-tpc/httpclient/issues) 给我们,当然,我们也非常欢迎你给我们提[PR](https://gitee.com/openharmony-tpc/httpclient/pulls)。 ## 开源协议 本项目基于 [Apache License 2.0](https://gitee.com/openharmony-tpc/httpclient/blob/master/LICENSE),请自由地享受和参与开源。