每一門語言都離不開網(wǎng)絡(luò)請求,有自己的一套Networking Api。React Native使用的是Fetch。 今天我們來談?wù)勁cFetch相關(guān)的一些事情。
purpose
通過這篇文章,你將了解到以下幾點(diǎn)關(guān)于Fetch的獨(dú)家報(bào)道
- Fetch的簡單運(yùn)用
- Fetch的主要Api
- Fetch使用注意事項(xiàng)
- Fetch的Promise封裝
fetch
fetch的使用非常簡單,只需傳入請求的url
fetch('https://facebook.github.io/react-native/movies.json');
當(dāng)然是否請求成功與數(shù)據(jù)的處理,我們還需處理成功與失敗的回調(diào)
function getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
}
通過response.json()將請求的返回?cái)?shù)據(jù)轉(zhuǎn)化成json數(shù)據(jù)以便使用。通過.then來對數(shù)據(jù)進(jìn)行轉(zhuǎn)化處理或最終暴露給調(diào)用者;.catch對異常的處理。
以上就是一個(gè)簡單的網(wǎng)絡(luò)請求,該請求默認(rèn)是get方式。那么post又該如何請求呢?
Api & Note
在fetch中我們直接傳入url進(jìn)行請求,其實(shí)內(nèi)部本質(zhì)是使用了Request對象,只是將url出入到了Request對象中。
const myRequest = new Request('https://facebook.github.io/react-native/movies.json');
const myURL = myRequest.url; // https://facebook.github.io/react-native/movies.jsonflowers.jpg
const myMethod = myRequest.method; // GET
fetch(myRequest)
.then(response => response.json())
.then(responseJson => {
//todo
});
如果我們需要請求post,需要改變Request的method屬性。
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
非常簡單,在url后直接傳入{}對象,其中指定method使用post。
相信大家應(yīng)該都知道get與post的一個(gè)主要區(qū)別是get可以在url上直接添加參數(shù),而post為了安全都不采用直接將參數(shù)追加到url上,而是使用body來傳給service端。
在使用body前,這里還需知道headers。下面某個(gè)post請求的headers信息

需要注意的是Content-Type字段,它代表的是service端接收的數(shù)據(jù)類型,圖片中使用的是application/x-www-form-urlencoded。這對于我們的body來說是非常重要的。只有匹配Content-Type的類型才能正確的傳遞參數(shù)信息。
示例的代碼使用的是application/json,所以body使用Json.stringify()進(jìn)行參數(shù)轉(zhuǎn)換,而對于Content-Type為application/x-www-form-urlencoded,需要使用queryString.stringify()。
Request中除了method、headers與body,還有以下屬性
- Request.cache: 請求的緩存模式(default/reload/no-cache)
- Request.context: 請求的上下文(audio/image/iframe)
- Request.credentials: 請求的證書(omit/same-origin/include)
- Request.destination: 請求的內(nèi)容描述類型
- Request.integrity: 請求的 subresource integrity
- Request.mode: 請求的模式(cors/no-cors/same-origin/navigate)
- Request.redirect: 請求的重定向方式(follow/error/manual)
- Request.referrer: 請求的來源(client)
- Request.referrerPolicy: 請求的來源政策(no-referrer)
- Request.bodyUsed: 聲明body是否使用在response中
請求成功之后,使用.then來轉(zhuǎn)換數(shù)據(jù),使用最多的是Body.json(),當(dāng)然你也可以使用以下的幾種數(shù)據(jù)轉(zhuǎn)換類型
- Body.arrayBuffer
- Body.blob
- Body.formData
- Body.text
以上是fetch請求相關(guān)的屬性與方法。如果你已經(jīng)有所了解,那么恭喜你對fetch的基本使用已經(jīng)過關(guān)了,下面對fetch的使用進(jìn)行封裝。
封裝
在實(shí)際開發(fā)中,url的host都是相同的,不同的是請求的方法名與參數(shù)。而對于不同的環(huán)境(debug|release)請求的方式也可能不同。例如:在debug環(huán)境中為了方便調(diào)試查看請求的參數(shù)是否正確,我們會使用get來進(jìn)行請求。所以在封裝之前要明確什么是不變的,什么是變化的,成功與失敗的響應(yīng)處理。
經(jīng)過上面的分析,羅列一下封裝需要做的事情。
- 不變的: host,headers,body.json()
- 變化的: url,method,body
- 響應(yīng)方式: Promise(resolve/reject)
function convertUrl(url, params) {
let realUrl = ApiModule.isDebug?
url + "?" + queryString.stringify(Object.assign({}, params, commonParams)) : url;
if (ApiModule.isDebug) {
console.log("request: " + realUrl);
}
return realUrl;
}
首先對url與參數(shù)params進(jìn)行拼接,如果為debug模式將params拼接到url后。這里使用到了Object.assign()將params與commonParams組合成一個(gè){}對象。最終通過queryString.stringify轉(zhuǎn)化成string。
ApiModule.isDebug是原生傳遞過來的值,對于Android/IOS只需傳遞自己的ApiModule即可。
function getMethod() {
return ApiModule.isDebug? "get": "post";
}
上述提到的get與post的請求時(shí)機(jī)。
const headers = {
Accept: 'application/json',
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
};
在headers中Content-Type類型為application/x-www-form-urlencode
function convertBody(params) {
return ApiModule.isDebug? undefined : queryString.stringify(Object.assign({}, params, commonParams));
}
由于debug模式使用的是get方式,但get規(guī)定是不能有body的,所以這里使用了undefined來標(biāo)識。同時(shí)為了匹配headers中的Content-Type,params的轉(zhuǎn)化必須使用queryString.stringify;如果接受的是json,可以使用JSON.stringify。
定義完之后fetch對外只需接受params參數(shù)即可。
async function fetchRequest(params){
let body = convertBody(params);
fetch(convertUrl(baseUrl, params),{
method: method,
headers: headers,
body: body
})
.then((response) => response.json())
.then((responseJson) => {
//todo success
})
.catch((error) => {
if (ApiModule.isDebug) {
console.error("request error: " + error);
};
//todo error
});
}
fetch的請求封裝完成,但我們的成功與失敗的狀態(tài)并沒有通知給調(diào)用者,所以還需要一個(gè)回調(diào)機(jī)制。Promise是一個(gè)異步操作最終完成或者失敗的對象。它可以接受兩個(gè)函數(shù)resolve、reject
const p = new Promise((resolve, reject){
...
//success
resolve('success')
//error
reject('error')
});
//use
p.then(success => {
console.log(success);
}, error => {
console.log(error)
});
將fetch請求放入到Promise的異步操作中,這樣一旦數(shù)據(jù)成功返回就調(diào)用resolve函數(shù)回調(diào)給調(diào)用者;失敗調(diào)用reject函數(shù),返回失敗信息。而調(diào)用者只需使用Promise的.then方法等候數(shù)據(jù)的回調(diào)通知。下面來看下完整的fetch封裝。
async function fetchRequest(params){
let body = convertBody(params);
return new Promise(function(resolve, reject){
fetch(convertUrl(baseUrl, params),{
method: method,
headers: headers,
body: body
})
.then((response) => response.json())
.then((responseJson) => {
resolve(responseJson);
})
.catch((error) => {
if (ApiModule.isDebug) {
console.error("request error: " + error);
};
reject(error);
});
});
}
之后對fetch的使用就非常簡單了,只需傳入需要的參數(shù)即可。
fetchRequest({method: "goods.getInfo", goodsId: 27021599158370074})
.then(res =>{
this.setState({
shareInfo: res.data.shareInfo
});
});
以上是有關(guān)fetch的全部內(nèi)容,當(dāng)然在React Native中還有其它的第三方請求庫:XMLHttpRequest,同時(shí)也支持WebSockets。感興趣的也可以去了解一下,相信會有不錯的收獲。
精選文章
5分鐘吃透React Native Flexbox
ViewDragHelper之手勢操作神器
自定義Android注解Part2:代碼自動生成
Bitmap的圖片壓縮匯總
拉粉環(huán)節(jié):感覺不錯的可以來一波關(guān)注,掃描下方二維碼,關(guān)注公眾號,及時(shí)獲取最新知識技巧。
