Skip to content

Commit

Permalink
feat: support display HTML format in API error responses
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Wang <[email protected]>
  • Loading branch information
ruibaby committed Dec 11, 2024
1 parent 0748ae4 commit fc8c8fe
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 24 deletions.
2 changes: 2 additions & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"fuse.js": "^6.6.2",
"jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21",
"object-hash": "^3.0.0",
"overlayscrollbars": "^2.5.0",
"overlayscrollbars-vue": "^0.5.7",
"path-browserify": "^1.0.1",
Expand Down Expand Up @@ -114,6 +115,7 @@
"@types/jsdom": "^20.0.1",
"@types/lodash-es": "^4.17.12",
"@types/node": "^18.11.19",
"@types/object-hash": "^3.0.6",
"@types/qs": "^6.9.7",
"@types/randomstring": "^1.1.8",
"@types/ua-parser-js": "^0.7.39",
Expand Down
54 changes: 33 additions & 21 deletions ui/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 37 additions & 1 deletion ui/src/components/upload/UppyUpload.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts" setup>
import { i18n } from "@/locales";
import type { ProblemDetail } from "@/setup/setupApiClient";
import { createHTMLContentModal } from "@/utils/modal";
import { Toast } from "@halo-dev/components";
import type { Restrictions } from "@uppy/core";
import Uppy, { type SuccessResponse } from "@uppy/core";
Expand All @@ -13,7 +14,8 @@ import zh_CN from "@uppy/locales/lib/zh_CN";
import zh_TW from "@uppy/locales/lib/zh_TW";
import { Dashboard } from "@uppy/vue";
import XHRUpload from "@uppy/xhr-upload";
import { computed, onUnmounted } from "vue";
import objectHash from "object-hash";
import { computed, h, onUnmounted } from "vue";
const props = withDefaults(
defineProps<{
Expand Down Expand Up @@ -91,6 +93,40 @@ const uppy = computed(() => {
const responseBody = response as XMLHttpRequest;
const { status, statusText } = responseBody;
const defaultMessage = [status, statusText].join(": ");
// Catch error requests where the response is text/html,
// which usually comes from a reverse proxy or WAF
// fixme: Because there is no responseType in the response, we can only judge it in this way for now.
const parser = new DOMParser();
const doc = parser.parseFromString(
responseBody.response,
"text/html"
);
if (
Array.from(doc.body.childNodes).some((node) => node.nodeType === 1)
) {
createHTMLContentModal({
uniqueId: objectHash(responseBody.response || ""),
title: responseBody.status.toString(),
width: 700,
height: "calc(100vh - 20px)",
centered: true,
content: h("iframe", {
srcdoc: responseBody.response,
sandbox: "",
referrerpolicy: "no-referrer",
loading: "lazy",
style: {
width: "100%",
height: "100%",
},
}),
});
return new Error(defaultMessage);
}
Toast.error(defaultMessage, { duration: 5000 });
return new Error(defaultMessage);
}
Expand Down
34 changes: 32 additions & 2 deletions ui/src/setup/setupApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { i18n } from "@/locales";
import { createHTMLContentModal } from "@/utils/modal";
import { axiosInstance } from "@halo-dev/api-client";
import { Dialog, Toast } from "@halo-dev/components";
import type { AxiosError } from "axios";
import objectHash from "object-hash";
import { h } from "vue";

export interface ProblemDetail {
detail: string;
Expand All @@ -16,7 +19,7 @@ export function setupApiClient() {
(response) => {
return response;
},
async (error: AxiosError<ProblemDetail>) => {
async (error: AxiosError) => {
if (error.code === "ERR_CANCELED") {
return Promise.reject(error);
}
Expand All @@ -41,7 +44,7 @@ export function setupApiClient() {
}

const { status } = errorResponse;
const { title, detail } = errorResponse.data;
const { title, detail } = errorResponse.data as ProblemDetail;

if (status === 401) {
Dialog.warning({
Expand All @@ -64,6 +67,33 @@ export function setupApiClient() {
return Promise.reject(error);
}

// Catch error requests where the response is text/html,
// which usually comes from a reverse proxy or WAF

const contentType = error.response?.headers["content-type"];

if (contentType === "text/html") {
createHTMLContentModal({
uniqueId: objectHash(error.response?.data || ""),
title: error.response?.status.toString(),
width: 700,
height: "calc(100vh - 20px)",
centered: true,
content: h("iframe", {
srcdoc: error.response?.data?.toString(),
sandbox: "",
referrerpolicy: "no-referrer",
loading: "lazy",
style: {
width: "100%",
height: "100%",
},
}),
});

return Promise.reject(error);
}

if (title || detail) {
Toast.error(detail || title);
return Promise.reject(error);
Expand Down
Loading

0 comments on commit fc8c8fe

Please sign in to comment.