一、Http請求數據
http模塊是鴻蒙內置的一個模塊,提供了網絡請求的能力。不需要再寫比較原始的AJAS代碼。
ps:在項目中如果要訪問網絡資源,不管是圖片文件還是網絡請求,必須給項目開放權限。
(1)網絡連接方式
HTTP數據請求連接:通過HTTP發起的一個單向數據請求。
WebSocket連接:使用WebSocket建立服務器與客戶端的雙向連接。
Socket連接:通過Socket進行數據傳輸,更加底層。
(2)涉及接口文檔
類型 | 說明 |
---|---|
http.createHttp() | 創建一個HTTP請求,里面包括發起請求、中斷請求、訂閱/取消訂閱HTTP Response Header事件。 |
HttpRequest() | 根據URL地址,發起HTTP網絡請求。 |
requestInStream() | 根據URL地址,發起HTTP網絡請求并返回流式響應,得到二進制數據,應用到文件下載,從后端拿到的不再是JSON和字符串,而是二進制數據。 |
destroy() | 中斷請求任務。 |
(3)request接口開發步驟?
1、步驟概述
1、從@kit.NetworkKit中導入http命名空間。Kit是我們項目需要用到的各種服務,如網絡服務,分布式管理服務,藍牙通信等。
2、調用creatHttp()方法,創建一個HttpRequest對象。
3、調用該對象的request()方法,訂閱http響應頭事件,此接口會比request請求先返回。可以根據業務需要訂閱此消息。(此步驟不是必須,是用來監控響應頭信息,如果你想發請求給后端,想要先知道后端返回的數據是JSON還是文件之類的,可以用此監控,他會比內容先返回客戶端。)
4、調用該對象的equest()方法,傳入http請求的url地址和可選參數,發起網絡請求。
5、得到結果過后,按照實際業務需要,解析返回結果,篩選或者進行數據轉化。
6、調用該對象的off()方法,取消訂閱http響應頭事件。
7、當請求使用完畢時,調用destroy()方法主動銷毀。
2、封裝代碼:
//在common模塊中封裝一個基礎的請求工具import { http } from "@kit.NetworkKit";//封裝請求代碼,考慮到以后每個模塊都要發送請求,默認放在common模塊中。
//1、導入
export function MyRequest(url:string,method:http.RequestMethod,requestData:string){//2、創建http請求const httpRequest = http.createHttp()//3、可以用httprequest監聽響應頭(不是必須)httpRequest.on('headersReceive', (header: Object) => {console.info('header: ' + JSON.stringify(header));});httpRequest.request(url, {method:method,//請求方式header:{//設置請求頭//前端瀏覽器告訴后端,前端傳遞的數據格式'Content-Type': 'application/json'},extraData:requestData, //設置請求要傳給后端的數據connectTimeout:9000, //前端發送數據給后端如果9秒沒有結果,前端主動終止行為readTimeout:9000, //讀取數據超過9秒,告訴前端請求失敗},(error:Error,data:http.HttpResponse)=>{//error沒有內容代表成功if (!error) {console.log(`請求成功,返回數據:${JSON.stringify(data)}`)// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}else {console.log(`請求失敗,具體原因:${JSON.stringify(error)}`)// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}})
}
?3、使用說明:
在頁面中要使用這個工具來測試請求是否成功,在common/index.ets文件中先暴露。
export {MyRequest} from './src/main/ets/utils/HttpUtils'
在home頁面或者組件中,引入對應的函數
import {MyRequest} from '@ohos/common'///比如跟事件綁定,測試數據是否能收到
.onClick((event:ClickEvent) => {MyRequest('http://47.98.128.191:4001/home/swiperdate',http.RequestMethod.GET,'')})
此時可以看到日志可以收到:
?此時請求發送完畢能夠得到后端數據,但請求不是直接在頁面或者組件中編寫的代碼,而是提取到了common模塊中,如何拿到服務端的數據并顯示到頁面上,這才是需要解決的問題。
4、泛型編程
typescript中非常重要的一個概念:泛型編程。
利用一個簡單的案例:
function computed(params1:number,params2:number):number{return params1 +params2
}computed(1,3)//編譯通過
computed('xiao','ming')//編譯失敗,因為只接受number類型
為了簡化上面的代碼,使代碼更加靈活,尤其是在數據約束上,既要增加約束,又要讓參數支持更多類型,或者更加靈活,設計方式便是采用泛型的方式來設計參數類型?。
function computed<T>(params1:T,params2:T):T{return params1 +params2
}computed<number>(1,3) //編譯通過
computed<string>('xiao','ming') //編譯通過
computed<bollean>(true,false) //編譯通過
同一個函數因為有了泛型,可以多次使用 ,這里我們以上面出現的問題:如何拿到服務端的數據并顯示到頁面上,利用promise來解決。通過promise對象將異步的請求代碼封裝到容器中獲取到結果。
import { http } from "@kit.NetworkKit";
//BasicConstants下暴露基礎URL地址,和傳入的資源路徑拼接
import { BasicConstants} from '../../constants/BasicConstants'
//封裝請求代碼,考慮到以后每個模塊都要發送請求,默認放在common模塊中。
//1、導入
export function MyRequest(url:string,method:http.RequestMethod,requestData:string){//2、創建http請求const httpRequest = http.createHttp()return new Promise((reslove:(value:string)=>void,reject:(value?:string)=>void)=>{//request發送請求就是異步代碼httpRequest.request(//不再簡單是url,而是做一下拼接基礎地址BasicConstants.BASE_URL+url,{method:method,//請求方式header:{//設置請求頭//前端瀏覽器告訴后端,前端傳遞的數據格式'Content-Type': 'application/json'},extraData:requestData, //設置請求要傳給后端的數據connectTimeout:9000, //前端發送數據給后端如果9秒沒有結果,前端主動終止行為readTimeout:9000, //讀取數據超過9秒,告訴前端請求失敗},(error:Error,data:http.HttpResponse)=>{//error沒有內容代表成功if (!error) {console.log(`請求成功,返回數據:${JSON.stringify(data,null,2)}`)reslove(JSON.stringify(data))// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}else {console.log(`請求失敗,具體原因:${JSON.stringify(error)}`)reject(JSON.stringify(error))// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}})})}
頁面中獲取請求返回的數據:?
?但此時傳入參數是固定必須是string類型,不夠靈活,接下來進一步封裝,利用泛型編程做進一步優化使得代碼實現復用。K代表請求的數據類型,T代表返回的數據類型
import { http } from "@kit.NetworkKit";
import { BasicConstants} from '../../constants/BasicConstants'
//封裝請求代碼,考慮到以后每個模塊都要發送請求,默認放在common模塊中。
//1、導入
//K代表請求的數據類型,T代表返回的數據類型
export function MyRequest<T,K>(url:string,method:http.RequestMethod,requestData?:K){//2、創建http請求const httpRequest = http.createHttp()return new Promise((reslove:(value:T)=>void,reject:(value?:string)=>void)=>{//request發送請求就是異步代碼httpRequest.request(//不再簡單是url,而是做一下拼接基礎地址BasicConstants.BASE_URL+url,{method:method,//請求方式header:{//設置請求頭//前端瀏覽器告訴后端,前端傳遞的數據格式'Content-Type': 'application/json'},extraData:JSON.stringify(requestData)||'', //設置請求要傳給后端的數據connectTimeout:9000, //前端發送數據給后端如果9秒沒有結果,前端主動終止行為readTimeout:9000, //讀取數據超過9秒,告訴前端請求失敗},(error:Error,data:http.HttpResponse)=>{//error沒有內容代表成功if (!error) {console.log(`請求成功,返回數據:${JSON.stringify(data,null,2)}`)//這里如何reslove(JSON.parse(data.result as string))// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}else {console.log(`請求失敗,具體原因:${JSON.stringify(error)}`)reject(JSON.stringify(error))// 取消訂閱HTTP響應頭事件。httpRequest.off('headersReceive');// 當該請求使用完畢時,開發者務必調用destroy方法主動銷毀該JavaScript Object。httpRequest.destroy();}})})}
?頁面中獲取請求返回的數據:?
完整工具封裝見資源文件。
(4)HTTP數據請求
4.1 導入HTTP模塊
import http from '@ohos.net.http';
4.2?使用HTTP模塊發送請求,處理響應.
4.2.1 創建一個http的請求對象,不可復用。
const httpRequest = http.createHttp()
4.2.2 調用一個request方法,發起網絡請求。
ps:像這種可能存在數據請求發送完但數據還沒收到,因此此處方法執行完會存放一個未來會完成的結果Promise。
req.request('http://localhost:3000/users',//請求URL地址
{ //請求選項HttpRequestOptionsmetnod:http.RequestMethod.GET,extraData:{'param1':'value1'} //k1=v1&k1=v2
}
) ?
HttpRequestOptions 說明:
名稱 類型 描述 method RequestMethod 請求方式,GET(查詢)、POST(表單提交,新增)、PUT(修改)、DELETE(刪除)等 extraData string|Object 請求參數 header Object 請求頭字段 connectTimeout number 請求超時時間,單位毫秒,默認60000ms readTimeout number 讀取超時間,同上
4.2.3?獲取服務器響應的內容,Promise提供兩種方法分別是then成功回調和catch失敗回調。
.then((resp:http.HttpResponse)=>{if(resp.responseCode === 200){//請求成功}})
.catch((err:Error)=>{//請求失敗
});
HttpResponse 說明:?
名稱 類型 描述 responseCode responseCode 響應狀態碼 header Object 響應頭 cookies string 響應返回的cookies result string|Object 響應體,默認是JSON字符串 resultType HttpDataType 返回值類型
二、Promise
Promise是es6提出的一個概念,主要用來解決異步回調的問題。Promise是一個數據容器,保存了未來的一個結果,Promise本身是可以用來存放同步代碼和異步代碼,平時經常用來解決存放異步代碼。以下是網絡請求的一個發展歷程:
發送網絡請求,獲取結果
1.1 發送網絡請求
//"AJAX"(Asynchronous JavaScript and XML,異步 JavaScript 和 XML)
//瀏覽器默認提供的對象,獲取結果
const xmlhttp = new XMLhttpRequest()
//連接服務器
xmlhttp.open('GET','http://+地址',true)
xmlhttp.send('id=1')//監聽狀態碼,當狀態碼是200時
xmlhttp.onreadystatechange = function(){//首先狀態碼必須是200,readyState代表xmlhttp加載過程if(xmlhttp.status == 200 && xmlhttp.readyState == 4){const result = xmlhttp.responseText//拿到數據后轉化const obj = JSON.parse(result)}
}
1.2 將其封裝工具
function ajas( {method='GET',url,data='',async=true} ){//"AJAX"(Asynchronous JavaScript and XML,異步 JavaScript 和 XML)//瀏覽器默認提供的對象,獲取結果const xmlhttp = new XMLhttpRequest()//連接服務器xmlhttp.open(method,url,async)xmlhttp.send(data)//監聽狀態碼,當狀態碼是200時xmlhttp.onreadystatechange = function(){//首先狀態碼必須是200,readyState代表xmlhttp加載過程if(xmlhttp.status == 200 && xmlhttp.readyState == 4){const result = xmlhttp.responseText//拿到數據后轉化const obj = JSON.parse(result)//這里return obj沒有意義,這里是個事件,時間返回的函數外面是接收不到的}}
//如果在fuction函數這里return obj也是不可以的,局部的變量無法在外部用
}//使用封裝工具
ajax({method:'GET',url:'http://+地址',data:'id = 1'async:true
})
此時的obj還不能調出來使用,這時解決方法:在函數中在傳入一個函數?success,如果函數能進入if中實現結果的取用,將在函數中調用。
function ajas( {method='GET',url,data='',async=true,success} ){//"AJAX"(Asynchronous JavaScript and XML,異步 JavaScript 和 XML)//瀏覽器默認提供的對象,獲取結果const xmlhttp = new XMLhttpRequest()//連接服務器xmlhttp.open(method,url,async)xmlhttp.send(data)//監聽狀態碼,當狀態碼是200時xmlhttp.onreadystatechange = function(){//首先狀態碼必須是200,readyState代表xmlhttp加載過程if(xmlhttp.status == 200 && xmlhttp.readyState == 4){const result = xmlhttp.responseText//拿到數據后轉化const obj = JSON.parse(result)success(Obj)}else if(404 500){error('失敗')}}
}//使用封裝工具
ajax({method:'GET',url:'http://+地址',data:'id = 1'async:true,success:function(msg){console.log(msg)}//是否請求成功error:function(error){}
})
?這樣做有缺陷:回調地獄,無限制的在回調函數中執行任務,得到回調結果,層層嵌套,開發中要避免,不存在可讀性。
//使用封裝工具
ajax({method:'GET',url:'http://+地址',data:'id = 1'async:true,success:function(msg){console.log(msg)ajax({url:'http://+地址',data:msg.id,success(msg2){ ajax({url:'',data:msg.classesId}//是否請求成功error:function(error){}
})
Promise
由上述Promise來解決異步編程的問題。?
//按照1234執行順序來執行,因為promise本身是同步的,如果在promise中放入一個異步的代碼,異步代碼是需要花時間,異步代碼不論花費多長時間,等到代碼運行結束,成功或者失敗都會存放在resolve,reject中。
console.log(1)
//resolve,reject 這兩個參數是函數
const promise = new Promise((resolve,reject)=>{
console.log(2)//存放同步代碼或者異步代碼,這里主要存放異步代碼ajas({url:'http://xxx',method:'POST',data:{id:1},success:(msg)=>{resolve(msg)},error:(error)=>{reject(error)}})
})//then這個函數是異步的,只有resolve執行完畢,then才會執行
promise.then((result)=>{console.log(4)
})
.catch(error=>{})console.log(3)
?await和async
es7提出的一個新方案,可以等待promise的結果。
//resolve,reject 這兩個參數是函數
const promise2 = new Promise((resolve,reject)=>{//存放同步代碼或者異步代碼,這里主要存放異步代碼ajas({url:'http://xxx',method:'POST',data:{id:1},success:(msg)=>{resolve(msg)},error:(error)=>{reject(error)}})
})async function show(){const res1 = await promise1const res2 = await promise2
}
?axios工具
在前面代碼的基礎上,第三方工具axios做了一件事情,將axios代碼和promise代碼進行了封裝,形成了一個完整的請求工具。
//封裝格式
class Axios{baseURL =''get(){return new Promise (()=>{resolve(xxx)reject(xxx)})}post(){}creat(){}
}export const axios = new Axios()//代碼中如何使用
import axios from 'axios'
//方法1:通過then拿到服務器響應回來的結果
axios.get('http://xxx').then(res=>{{)
//方法2:通過await和async配合拿到服務器響應回來的結果
result = await axios.post('http://xxx')
作為一個第三方庫,使用的時候需要先完成下包的操作,打開終端執行命令,ohpm 是一個包管理工具,用來管理鴻蒙提供的第三方模塊。