Browse Source

feat[service]: 处理错误消息

chenlei 1 year ago
parent
commit
5752aca524

+ 16 - 0
packages/service/src/error.test.ts

@@ -0,0 +1,16 @@
+import { ResponseError } from "./error";
+import { DageResponse } from "./types";
+
+test("ResponseError", () => {
+  const response = {
+    errorMessage: "请求失败",
+    data: "test",
+    errorCode: -1,
+  } as DageResponse;
+  const error = new ResponseError(response);
+  expect(error.code).toBe(-1);
+  expect(error.message).toBe("请求失败");
+  expect(error.response).toBe(response);
+  expect(error.stack).toBeTruthy();
+  expect(error instanceof Error).toBe(true);
+});

+ 29 - 0
packages/service/src/error.ts

@@ -0,0 +1,29 @@
+import { DageResponse } from "./types";
+
+/**
+ * 响应错误对象
+ */
+export class ResponseError extends Error {
+  public code: number;
+  public response: DageResponse;
+
+  constructor(response: DageResponse) {
+    super(response.errorMessage ?? "请求失败");
+    this.code = response.errorCode ?? -1;
+    this.response = response;
+  }
+}
+
+/**
+ * 判断错误对象是否为响应错误对象。 用于 catch 语句安全地获取 code 和 message
+ * @param error
+ * @returns
+ */
+export function isResponseError(error: unknown): error is ResponseError {
+  return !!(
+    error &&
+    typeof error === "object" &&
+    "code" in error &&
+    "message" in error
+  );
+}

+ 14 - 8
packages/service/src/request.test.ts

@@ -61,7 +61,10 @@ test("request", async () => {
 
   expect(fetch).toBeCalledWith("https://example.com/test?one=two", {
     body: '{"foo":"bar"}',
-    headers: { "content-type": "application/json", "x-power-by": "test" },
+    headers: {
+      "content-type": "application/json;charset=UTF-8",
+      "x-power-by": "test",
+    },
     method: "PUT",
     mode: "cors",
   });
@@ -78,7 +81,7 @@ test("name 参数变量替换", async () => {
 
   expect(fetch).toBeCalledWith("https://example.com/test/123/baz", {
     body: '{"id":"123","foo":{"bar":"baz"}}',
-    headers: { "content-type": "application/json" },
+    headers: { "content-type": "application/json;charset=UTF-8" },
     method: "POST",
     mode: "cors",
   });
@@ -134,7 +137,10 @@ test("拦截器", async () => {
     "https://example.com/test?bar=bar&foo=foo&one=two",
     {
       body: undefined,
-      headers: { "content-type": "application/json", "x-power-by": "test" },
+      headers: {
+        "content-type": "application/json;charset=UTF-8",
+        "x-power-by": "test",
+      },
       method: "GET",
       mode: "cors",
     }
@@ -157,7 +163,7 @@ test("拦截器元数据", async () => {
   request("/test", {}, { meta: { foo: "bar" } });
   expect(interceptor.mock.calls[0][0]).toEqual({
     body: {},
-    headers: { "content-type": "application/json" },
+    headers: { "content-type": "application/json;charset=UTF-8" },
     // 拦截到元数据
     meta: { foo: "bar" },
     method: "POST",
@@ -167,7 +173,7 @@ test("拦截器元数据", async () => {
 
   expect(fetch).toBeCalledWith("https://example.com/test", {
     body: "{}",
-    headers: { "content-type": "application/json" },
+    headers: { "content-type": "application/json;charset=UTF-8" },
     method: "POST",
     mode: "cors",
   });
@@ -192,13 +198,13 @@ test("拦截重试, 用于重新登录等复杂场景", async () => {
   // fetch 被调用两次
   expect(fetch).toBeCalledWith("https://example.com/test", {
     body: '{"time":1}',
-    headers: { "content-type": "application/json" },
+    headers: { "content-type": "application/json;charset=UTF-8" },
     method: "POST",
     mode: "cors",
   });
   expect(fetch).toBeCalledWith("https://example.com/test", {
     body: '{"time":2}',
-    headers: { "content-type": "application/json" },
+    headers: { "content-type": "application/json;charset=UTF-8" },
     method: "POST",
     mode: "cors",
   });
@@ -319,7 +325,7 @@ test("变量替换", async () => {
   expect(fetch).toBeCalledWith("https://example.com/test?myId=mock&one=two", {
     body: '{"foo":"bar","myId":"mock"}',
     headers: {
-      "content-type": "application/json",
+      "content-type": "application/json;charset=UTF-8",
       "x-power-by": "test",
       "my-id": "mock",
     },

+ 9 - 0
packages/service/src/request.ts

@@ -21,6 +21,7 @@ import {
   serializeBody,
   serializeResponseBody,
 } from "./utils";
+import { ResponseError } from "./error";
 
 export interface ServiceAdapter {
   baseURL: string;
@@ -75,6 +76,14 @@ export function createService() {
       };
     }
 
+    if (response.errorMessage) {
+      throw new ResponseError({
+        ...response,
+        errorMessage: response.errorMessage ?? "请求失败",
+        errorCode: response.errorCode ?? -1,
+      });
+    }
+
     return response;
   }