您好,登錄后才能下訂單哦!
這篇文章主要講解了“JavaScript怎么安全的進行數據獲取”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript怎么安全的進行數據獲取”吧!
fetch
可能是我們在 JavaScript 獲取數據最常見的方式。
但是,我們用fetch
獲取數據的的代碼很有可能存在安全問題:
代碼示例:
const res = await fetch('/user') const user = await res.json()
上面這段代碼雖然簡單好用,但存在許很多問題。
問題一、缺少“錯誤處理”
當然你可能會說這個問題很好解決嘛,給她添加一個try/catch
就好了,遇到錯誤就會拋出了嘛!
代碼示例:
try { const res = await fetch('/user') const user = await res.json() } catch (err) { // 處理錯誤的代碼 }
當然,這樣可以確實可以對我們的錯誤進行處理了。遇到錯誤的時候也會拋出,但是就算這樣寫了還是存在很多的問題,對錯誤的覆蓋能力不全面。
問題二:無法識別部分錯誤代碼
在這里,我們假設user
實際上是一個用戶對象。我們假設我們得到了響應200
。
但是fetch
不會針對非 200 的狀態拋出錯誤,因此如果你收到了400
(錯誤請求)、401
(未授權)、404
(未找到)、500
(內部服務器錯誤)或各種其他問題都不會進行錯誤拋出。
那你可能有會說了那我們用個if進行判斷然后對不同的錯誤碼進行分類處理不就好了!
于是我們就有了下面的代碼
try { const res = await fetch('/user') if (!res.ok) { switch (res.status) { case 400: /* 錯誤處理 */ break case 401: /* 錯誤處理 */ break case 404: /* 錯誤處理 */ break case 500: /*錯誤處理 */ break } } // User 已經是我們最新的數據了 const user = await res.json() } catch (err) { // 錯誤處理 }
現在,我們算是基本實現了fetch
對數據的安全獲取了. 但是這樣寫是很臃腫且笨重的,因為每次都必須重寫寫一次錯誤的處理邏輯,而如果是團隊開發的話對每個成員的要求會更高,要求每個同事都要按照同樣的邏輯來處理請求。而且在可讀性方面,也是很差的,維護起來很麻煩。
那么我們可不可以換一種更優雅的方式來處理我們的邏輯代碼呢?
我們可以使用throw
來處理我們的不同的錯誤響,而不是使用switch/case
.
try { const res = await fetch('/user') if (!res.ok) { throw new Error('錯誤的響應') } const user = await res.json() } catch (err) { // 錯誤處理 }
但是我們還剩下最后一個問題——就是當我們需要處理錯誤時,我們丟失了很多有用的上下文。我們無法在 catch 塊中訪問,因此查看處理錯誤時我們上并不知道響應的狀態代碼或錯誤的詳細信息。
這會讓我們debug變的很困難,很難去查錯。那我們要怎么才能拿到error的上下文呢?
最好的方法可能是創建我們自己的自定義錯誤類,并且在錯誤類中轉發響應的詳細信息:
代碼:
class ResponseError extends Error { constructor(message, res) { super(message) this.response = res } } try { const res = await fetch('/user') if (!res.ok) { throw new ResponseError('錯誤的響應信息(error的上下文信息)', res) } const user = await res.json() } catch (err) { //我們可以拿到錯誤的詳細信息,也就是error的上下文 switch (err.response.status) { case 400: /* 錯誤處理 */ break case 401: /* 錯誤處理 */ break case 404: /* 錯誤處理 */ break case 500: /* 錯誤處理 */ break } }
現在我們保留狀態代碼等error信息,這樣可以讓我們的用戶了解錯誤的原因的也能讓我們更好的處理錯誤。
例如,我們可以提醒用戶500
我們遇到了問題,并可以讓客戶聯系我們的進行解決。
或者如果狀態為401
,則他們當前未授權,可能需要重新登錄等。
雖然上面的代碼可以解決我們的所有問題,但是它仍然存在一個不穩定性,就是代碼的健壯性取決于開發人員的個人素質和能力。我們的的請求安全并不能等到統一的保障。
我們可以對我們代碼進行封裝,然后使用時進行導出引用就行了
class ResponseError extends Error { constructor(message, res) { this.response = res } } export async function myFetch(...options) { const res = await fetch(...options) if (!res.ok) { throw new ResponseError('錯誤響應的信息', res) } return res }
然后我們可以按下面的方式去使用它:
try { const res = await myFetch('/user') const user = await res.json() } catch (err) { // 錯誤的處理代碼 }
在我們的封裝代碼中,最好確保有一個統一的方式來處理錯誤。因為這里面包括給用戶的警報、日志記錄等。
當然如果我們的水平還沒有達到可以自己封裝一個完善的請求類時我們也可以去網上使用一些別封裝好的請求類,
axios是一個非常流行的 JS 請求數據的庫,它已經幫我們解決了上面我們探討的幾個問題。
try { const { data } = await axios.get('/user') } catch (err) { // 錯誤處理代碼 }
我覺得 Axios 的唯一缺點是包太大,如果我們只是在一個項目獲取一個很簡單的數據時使用axios
需要引入一個11kb的包,,反而會使我們的項目變的臃腫。
如果你覺得項目的大小對你更重要是你可以選擇Redaxios
Redaxios使用有 Axios 一樣的 API,但不到大小卻不到[1kb]
import axios from 'redaxios' // use as you would normally
還有一個不錯的選項是Wretch,它是 Fetch封裝成的一個非常小的包,和 Redaxios 一樣。Wretch 的特別之處在于它在很大程度上還原了原生的數據請求方法,但是它幫我們封裝了很多的錯誤處理代碼。
const user = await wretch("/user") .get() // Handle error cases in a more human-readable way .notFound(error => { /* ... */ }) .unauthorized(error => { /* ... */ }) .error(418, error => { /* ... */ }) .res(response => /* ... */) .catch(error => { /* uncaught errors */ })
感謝各位的閱讀,以上就是“JavaScript怎么安全的進行數據獲取”的內容了,經過本文的學習后,相信大家對JavaScript怎么安全的進行數據獲取這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。