博客 / 詳情

返回

淺談springboot和angular項目中異常處理的不足

場景

在我的第一個生產項目中前端顯示的報錯提示不太友好:

  1. 我們在進行釘釘用户同步時,操作電腦的出口ip不在白名單內時,前端的提示有兩個。
  2. 內容對用户不太友好(第一個提示沒有比較有效的信息)。
  3. 第二個提示的報錯內容明顯和我想要的提示不一致。
  4. image.png
    後台的日誌:(我需要的提示)
    image.png

    代碼復現

    public List<OapiV2UserListResponse.ListUserResponse> getDingdingUserList(Long deptId, Long cursor) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
            OapiV2UserListRequest oapiV2UserListRequest = new OapiV2UserListRequest();
            oapiV2UserListRequest.setDeptId(deptId);
            oapiV2UserListRequest.setCursor(cursor);
            oapiV2UserListRequest.setSize(10L);
            oapiV2UserListRequest.setOrderField("modify_desc");
            oapiV2UserListRequest.setContainAccessLimit(false);
            oapiV2UserListRequest.setLanguage("zh_CN");
            // 發起請求
            OapiV2UserListResponse oapiV2UserListResponse = client.execute(oapiV2UserListRequest, getAccessToken());
            // 打印日誌
            System.out.println(oapiV2UserListResponse.getResult().getHasMore());
            System.out.println(oapiV2UserListResponse.getResult().getList());
            List<OapiV2UserListResponse.ListUserResponse> list = oapiV2UserListResponse.getResult().getList();
            // 如果還有,就遞歸
            if (oapiV2UserListResponse.getResult().getHasMore()) {
                list.addAll(getDingdingUserList(deptId, oapiV2UserListResponse.getResult().getNextCursor()));
                return list;
            }
            // 沒有了就返回list
            return list;
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return null;
    }

這裏可以看出兩個問題:

  1. 我這裏做了一個catch的處理,我認為他是可以捕獲到白名單不對的異常,但是很明顯沒有走到catch塊,報錯信息不是在這個service發出的(是topsdk)。
  2. 前端獲取的異常,發生在這裏。

     // 打印日誌
    System.out.println(oapiV2UserListResponse.getResult().getHasMore());

    所以我們可以這樣修改代碼:

    public List<OapiV2UserListResponse.ListUserResponse> getDingdingUserList(Long deptId, Long cursor) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
            OapiV2UserListRequest oapiV2UserListRequest = new OapiV2UserListRequest();
            oapiV2UserListRequest.setDeptId(deptId);
            oapiV2UserListRequest.setCursor(cursor);
            oapiV2UserListRequest.setSize(10L);
            oapiV2UserListRequest.setOrderField("modify_desc");
            oapiV2UserListRequest.setContainAccessLimit(false);
            oapiV2UserListRequest.setLanguage("zh_CN");
            OapiV2UserListResponse oapiV2UserListResponse = client.execute(oapiV2UserListRequest, getAccessToken());
            // 單獨去處理異常
            if (!oapiV2UserListResponse.isSuccess()) {
                this.logger.error("Failed to get user list: {}", oapiV2UserListResponse.getErrmsg());
                throw new ValidationException(oapiV2UserListResponse.getErrmsg());
            }
            System.out.println(oapiV2UserListResponse.getResult().getHasMore());
            System.out.println(oapiV2UserListResponse.getResult().getList());
            List<OapiV2UserListResponse.ListUserResponse> list = oapiV2UserListResponse.getResult().getList();
            // 如果還有,就遞歸
            if (oapiV2UserListResponse.getResult().getHasMore()) {
                list.addAll(getDingdingUserList(deptId, oapiV2UserListResponse.getResult().getNextCursor()));
                return list;
            }
            // 沒有了就返回list
            return list;
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return null;
    }

解決思路是:手動拋出異常,這樣前端即可獲取想要的提示,也不會因為返回的響應對象沒有對應值而報錯。

追蹤源碼

為什麼請求失敗沒有被catch塊的代碼捕獲呢?
點擊到DefaultDingTalkClient的實現類中。發現其中發起請求的方法如下:
(這裏小編已經將執行的方法標紅了,且湊巧的是執行順序是從上到下)
image.png
我們仔細觀察可以找到後台日誌中顯示信息的代碼(且沒有拋出異常):
截圖 2025-11-19 16-05-54.png
image.png
debug獲取的參數信息:
截圖 2025-11-19 16-06-01.png

總結

原因找到了:就是對於釘釘的這個接口來説,他不認為請求ip不在白名單時需要拋出異常,只需要在後台日志提醒以下就好了。
當然還有一個問題:我們一次異常拋出導致兩個報錯提示(全局錯誤處理攔截器和angular http請求的錯誤都觸發了彈出提示框的方法),還有一個只有簡單的請求url和狀態碼(這個產生原因是全局錯誤處理器調用彈出提示框方法時傳入的參數不對導致的)
對以上問題處理後:
image.png

開發經驗

  • 由此可知我們開發的時候不應該想當然的去寫,就像我們認為釘釘請求失敗的時候就會報錯,但時計上不會。
  • 對於異常類,我們可以認為在特定場景下它會拋出。但是實際上這並不是一定的,取決於調用的方法是否拋出,人為因素更多一些,有些api就是不按照規範去拋出異常。
  • 不過對於這種問題還是直接看官方文檔更好一些。
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.