iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
自我挑戰組

SPYxFRONTEND ~ 懂一點後端真是讓人哇哭哇哭系列 第 28

[Day28] 前端查案系列(3)~來找出真正的兇手吧!‧ 資料修改失敗事件 (通靈程度:★★★)

  • 分享至 

  • xImage
  •  

前言

今天的文章一樣也是前端查案系列,
預計是這個系列的最後一篇,
來看看今天小鐵會報什麼樣厲害的案子吧XD

(PS1. 檔案結構一樣可參考前天文章,今天就不再貼一次了)
(PS2. 鐵人餐廳的系統從今天開始多了「編輯資料」跟「刪除資料」功能XD)
https://ithelp.ithome.com.tw/upload/images/20220929/2012987319a5y65KkW.png

本日正文

故事:為什麼部份資料無法修改成功?

今日登場人物:
小鐵 - 鐵人餐廳的服務生
小前 - 鐵人餐廳系統的前端擔當
小後 - 鐵人餐廳系統的後端擔當

這天小前要下班時偷瞄了小鐵一眼,
還特地偷偷從他位子後方準備要開溜,
結果小鐵一個冷不防往後轉,
馬上抓到要開溜的現行犯小前。

小鐵:「小前~~~~~~~~ 你不要走~~~~~」
小前:「...唉,既然都被你抓到了,你說吧,又遇到什麼問題了?」

小鐵:「事情是這樣的,感謝你們前陣子開發編輯資料的功能給我用,
我再也不用擔心自己手殘打錯資料了,
但是!」

人生最重要就是這個 BUT。

小鐵:「但是你看看最新這筆肉粽
其實品項跟數量我都打錯了orz
應該是菜粽,數量不小心多打了一個0...」

小前聽了聽,覺得目前沒聽到什麼問題啊。
「那就修改成正確的就好?」

小鐵:「對,所以你來看看,我剛試著要編輯,
品項是可以成功改成菜粽,但是數量怎樣都改不過來啦~~~」
(以下是小鐵的操作過程)

小前:「真的耶,那我來看看是怎麼回事好了。」
小鐵:「再麻煩你了~~~ 我今天能不能早點下班就看你的了!」

小前的坎坷查案流程

「又是一個沒噴錯的問題orz 又要我通靈了嗎orz」--小前心裡的OS。

總之先試著跟小鐵做一樣的操作看看吧!

嗯沒錯,果然是一樣的結局。

好吧,只能先來看一下編輯資料的 function 怎麼寫的,
首先到 App.js 搜尋 編輯資料 會找到這段:

<Link to={`/edit`}>
    <Button variant="link" size="sm" color="blue.500" onClick={() => { setSaleData(x);}}>編輯資料</Button>
</Link>

這個按鈕點擊後只有執行 setSaleData
所以看來跟它比較沒關係,
而是點了之後會連到 /edit
那再往下搜尋 /edit
會發現這段:

<Router>
    <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/admin" element={<AdminPage />} />
        <Route path="/edit" element={<EditPage />} />
    </Routes>
</Router>

看來編輯資料的主要邏輯寫在 <EditPage /> 這裡,
那就繼續用 EditPage 往下搜尋:

const EditPage = () => {
  return (
      <div>
        <Link to={`/`}>
          <Button colorScheme="blue">回前台</Button>
        </Link>
        <Text my={4} as="h2" fontSize="2xl" textAlign="center">
          {today.getFullYear()} 鐵人餐廳 - 編輯資料
        </Text>
        <form onSubmit={handleSubmit(submit)}>
          <FormLabel my={4}>品項</FormLabel>
          <Input placeholder='請輸入品項' type="text" {...register("item", { required: true })} />
          <FormLabel my={4}>數量</FormLabel>
          <Input placeholder='請輸入數量' type="number" {...register("count", { required: true })} />
          <Input placeholder='請輸入品項' type="text" {...register("comment", { required: true })} /> */}
          <Button my={4} type="submit">送出</Button>
        </form>
      </div>
  )
}

看到這邊小前發現跟新增資料的頁面幾乎一樣,
還是想不出個所以然,
只能先到送資料後會執行的 submit 看看。

const submit = data => {
    const count = parseInt(data.count, 10);
    data.count = count;
    axios.patch(`${hostUrl}/sales/${saleData.id}`, data)
    .then(res => {
      console.log(res.data);
      Swal.fire({
        title: '編輯資料成功',
        // text: err,
        icon: 'success',
        confirmButtonText: '確定'
      })
    })
    ... (略)
}

看到這裡小前還是沒有頭緒,但他靈光一閃想到,
「難道是前端沒送值給 API 嗎?」
這邊埋 console.log 來看看前端 call axios.patch 所送的資料是什麼吧!
(PS. axios.patch 的部份記得先註解掉)

const submit = data => {
    const count = parseInt(data.count, 10);
    data.count = count;
    console.log(data);
    ... (略)
}

https://ithelp.ithome.com.tw/upload/images/20220929/20129873GmleJ4dAyI.png

怪了,前端有送 API count,而且送的值也是畫面上的 60 啊....

小前一路追到這裡,卻還是找不到原因,
「看來還是找後端大大報案好了.....」

不!不能輕言放棄!
「一樣再來看一下 API 的 code,說不定能看到什麼可疑的地方。」
小前打開 API 的 server.js 檔案,
但該用什麼關鍵字當搜尋呢?

因為這次是 call axios.patch,那就用 patch 搜搜看吧!
https://ithelp.ithome.com.tw/upload/images/20220929/201298737l83r15Ci0.png

patch 可以找到這段:

else if (req.method === 'PATCH') {
    req.body = formatSale(req.body);
    next(); 
  }

req.body 是指 request 的內容,
request 就是指前端送給 API 的要求,
req.body = formatSale(req.body)
看來 API 有做什麼處理哦!

formatSale 繼續搜下去,
可以找到這段:

function formatSale(sale) {
  const fields = ['item'];
  Object.keys(sale).forEach((s) => {
    if (!fields.includes(s)) {
      delete sale[s];
    }
  });
  return sale;
}

一開始先去宣告 fields,裡面現在有 item
再來用迴圈一個一個帶出 sale 的 key 值,
再一個一個跟 fields 比對,
如果不存在於 fields
delete sale[s] 就把該 key 值刪掉....

還記得上面 formatSale(req.body) 是用 req.body 去代入,
也就是說,
req.body 裡面的 key 值 (有 item, count),
fields 只會跟 item 比對成功,
所以 count 就被刪掉了,
也就是說,這段只會處理 item 的要求。

抓到!皇天不負苦心人,終於被小前發現了!
這下終於可以把鍋推給後端了吧

好啦,但還是要向後端了解一下為什麼他會這樣寫。
小前去找了後端─小後,
小後聽完事情的始末之後表示:
「哦,這個當初的需求說,品項(item)不能修改,只有數量(count)會修改,
所以我才會只卡 count 可以修改,其它前端你這邊送什麼值我是不會理的。」

小前:「哦,原來如此。」
小後:「那你再跟他確定一下,如果有需求要改品項的話,那我這邊來修改一下邏輯。」

小前又去找了小鐵,跟他說原因並確認需求,
小鐵表示當然需要可以修改品項啊,因為他無法保證他會不會手殘打錯字orz

總之經過小後修改之後 (註:就是把 item 加入 fields 讓它比對得到),
我們再來看看如何吧!

小鐵、小前、小後:「耶!編輯成功!下班!」

恭喜一天又平安的過去了!
再次感謝 飛天小女警 小前的努力XD

(See you next time...)

整理查案流程

  1. 跟使用者做同樣的動作(輸入資料)看看
  2. 試著輸入不同值看看
  3. console.log 看前端拋給 API 的資料看看有沒有異常
  4. 稍微簡單搜尋 API 的 code 看看有沒有可疑的蛛絲馬跡
    (PS. 前端在看 API 的 code 只要看個大概,
    不用每一行都要弄得很懂,畢竟我們不是專業的後端orz)
    (5.如果4再不行可能真的得跟後端報案了orz)

參考文章

4 - Add JSON server

一些額外閒聊(?

因為前端送多餘的值嚴格來說不算是什麼錯誤,
所以 API 不會回 HTTP 狀態碼也是合理,
呼應先前文章所說,這種不會噴錯的問題真的是最難看出原因的orz
其實這是改編自我前陣子遇到的真實事件XD
一開始收到 user 報案說某個欄位一直修改不成功,
我自己也一度懷疑是我這邊前端沒處理好,
結果一路追下去才發現是 API 那邊有設定接收的資料欄位,
當然報給後端看一定也是看得出來,
只是前端這邊如果能先看出來,
就可以直接跟後端請他修改哪邊,
省去後端自己再從頭看一遍的時間,
可以更快速解決 user 遇到的問題XD

後記

終於迎來最後兩篇文章~~~~


上一篇
[Day27] 前端查案系列(2)~來找出真正的兇手吧!‧ 資料顯示異常事件 (通靈程度:★★)
下一篇
[Day29] 如果能夠早點知道就好了!前端人該會用的測試 API 神器~Postman
系列文
SPYxFRONTEND ~ 懂一點後端真是讓人哇哭哇哭30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言