使用fetch犯的错误

37 阅读1分钟

背景

在用大模型做一个对话应用时,因为要输出stream,所以只能用fetch,传统的xmlrequest无法实现。

使用过程

后端代码:

 const encoder = new TextEncoder();
    const decoder = new TextDecoder();
    const response = await fetch('https://api.openai.com/v1/chat/completions', fetchOptions)
    const stream = new ReadableStream({
        async start(controller) {
          const onParse = (event: ParsedEvent | ReconnectInterval) => {
            if (event.type === 'event') {
              const data = event.data;
    
              try {
                const json = JSON.parse(data);
                if (json.choices[0].finish_reason != null) {
                  controller.close();
                  return;
                }
                const text = json.choices[0].delta.content;
                const queue = encoder.encode(text);
                controller.enqueue(queue);
              } catch (e) {
                controller.error(e);
              }
            }
          };
          const parser = createParser(onParse);
     
          for await (const chunk of response.body as any) {
            parser.feed(decoder.decode(chunk));
          }
        },
      });
    return new Response(stream)
  };

前端代码:

        const controller = new AbortController();
        const chatRes = await fetch('/api/chat/', {
          method: 'post',
          body: body,
          signal: controller.signal
        })
        const data = chatRes.body;
        const reader = data!.getReader();
        const decoder = new TextDecoder();
        let done = false;
        let text = '';
        while (!done) {
          const { value, done: doneReading } = await reader.read();
          done = doneReading;
          const chunkValue = decoder.decode(value);
          text += chunkValue;
          console.log(text);
        }

由于前端body参数错误,导致大模型返回了错误,后端代码也没有报错,结果前端读流读不出来。

 const { value, done: doneReading } = await reader.read();
 这个value是undefined,done直接是true

按照正常思路,如果是传统的json格式一定会解析错误,很容易就能知道参数有问题,变成流以后,错误也是流的方式,只不过读取不到值,因此排查比较困难。

解决

在后端代码那一部分:

    const response = await fetch('https://api.openai.com/v1/chat/completions', fetchOptions)
    // 加上一个状态判断就ok了,如果是没有问题的,openai默认正确的都是200,错误的就不是流的方式,直接是json的方式,因此加了一个类似异常捕获。
    if (response.status !== 200) {
        const text = await response.text()
        throw new Error(text)
    }

最后

写fetch无论是不是流的方式,最好都加一个异常判断,这样错误容易及早发现。