Browse Source

feat: fetch stream compatibility enhance (#1551)

Ricky 1 year ago
parent
commit
657334a5fd
4 changed files with 33 additions and 2 deletions
  1. 4 1
      web/global.d.ts
  2. 1 0
      web/package.json
  3. 7 1
      web/service/base.ts
  4. 21 0
      web/utils/stream.ts

+ 4 - 1
web/global.d.ts

@@ -1,2 +1,5 @@
 declare module 'lamejs';
-declare module 'react-18-input-autosize';
+declare module 'react-18-input-autosize';
+declare module 'fetch-readablestream' {
+  export default function fetchReadableStream(url: string, options?: RequestInit): Promise<Response>
+}

+ 1 - 0
web/package.json

@@ -36,6 +36,7 @@
     "echarts": "^5.4.1",
     "echarts-for-react": "^3.0.2",
     "emoji-mart": "^5.5.2",
+    "fetch-readablestream": "^0.2.0",
     "i18next": "^22.4.13",
     "i18next-resources-to-backend": "^1.1.3",
     "immer": "^9.0.19",

+ 7 - 1
web/service/base.ts

@@ -1,8 +1,11 @@
+import fetchStream from 'fetch-readablestream'
 import { API_PREFIX, IS_CE_EDITION, PUBLIC_API_PREFIX } from '@/config'
 import Toast from '@/app/components/base/toast'
 import type { MessageEnd, MessageReplace, ThoughtItem } from '@/app/components/app/chat/type'
+import { isSupportNativeFetchStream } from '@/utils/stream'
 
 const TIME_OUT = 100000
+const supportNativeFetchStream = isSupportNativeFetchStream()
 
 const ContentType = {
   json: 'application/json',
@@ -220,6 +223,9 @@ const baseFetch = <T>(
   if (body && bodyStringify)
     options.body = JSON.stringify(body)
 
+  // for those do not support native fetch stream, we use fetch-readablestream as polyfill
+  const doFetch = supportNativeFetchStream ? globalThis.fetch : fetchStream
+
   // Handle timeout
   return Promise.race([
     new Promise((resolve, reject) => {
@@ -228,7 +234,7 @@ const baseFetch = <T>(
       }, TIME_OUT)
     }),
     new Promise((resolve, reject) => {
-      globalThis.fetch(urlWithPrefix, options as RequestInit)
+      doFetch(urlWithPrefix, options as RequestInit)
         .then((res) => {
           const resClone = res.clone()
           // Error handler

+ 21 - 0
web/utils/stream.ts

@@ -0,0 +1,21 @@
+// https://developer.chrome.com/articles/fetch-streaming-requests/#feature-detection
+export const isSupportNativeFetchStream = () => {
+  const supportsRequestStreams = (() => {
+    let duplexAccessed = false
+
+    const params = {
+      body: new ReadableStream(),
+      method: 'POST',
+      get duplex() {
+        duplexAccessed = true
+        return 'half'
+      },
+    }
+
+    const hasContentType = new Request('', params).headers.has('Content-Type')
+
+    return duplexAccessed && !hasContentType
+  })()
+
+  return supportsRequestStreams
+}