废话不多说直接上代码
1.PC端
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 60000) // 60秒超时,内容多可以加
const response = await fetch('https://you.com', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'text/event-stream',
},
body: JSON.stringify(params),
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
throw new Error(`请求错误,状态码: ${response.status}`)
}
if (!response.body) {
throw new Error('ReadableStream not supported')
}
const reader = response.body.getReader()
const decoder = new TextDecoder()
let result = ''
const MAX_LENGTH = 500000 // 设置最大字符数限制
const processStream = async () => {
try {
const { done, value } = await reader.read()
if (done) return
const text = decoder.decode(value, { stream: true })
// 限制结果大小
if (result.length + text.length <= MAX_LENGTH) {
result += text
setChatResult(result)
await processStream()
} else {
reader.cancel()
messageApi.warning('内容已达到最大限制')
}
} catch (error) {
const err = error as { name: string; message: string }
console.error('生成文章失败:', err)
messageApi.error(err.name === 'AbortError' ? '请求超时,请重试' : '生成文章失败,请重试')
} finally {
setChatLoading(false)
}
}
await processStream()
} catch (error) {
const err = error as { name: string; message: string }
messageApi.error(err.name === 'AbortError' ? '请求超时,请重试' : '生成文章失败,请重试')
} finally {
}
2. 小程序端
const requestTask = wx.request({
url: 'https://your.com',
method: 'POST',
data: params, // 请求参数
enableChunked: true, // 开启分块传输模式
responseType: 'arraybuffer', // 必须使用二进制格式接收
header: {
'Content-Type': 'application/json',
},
})
// 监听分块数据回调
requestTask.onChunkReceived((res) => {
const arrayBuffer = res.data
let rawStr = wx.arrayBufferToBase64(arrayBuffer)
rawStr = base64ToUtf8(rawStr) // 自定义Base64转UTF-8
if (rawStr) {
const result = rawStr
setAiReplyValue((prev) => prev + result)
}
})
base64ToUtf8函数
function base64ToUtf8(base64Str) {
try {
// 确保输入是有效的base64字符串
const cleanedBase64 = base64Str.replace(/\s/g, '');
// 使用微信小程序的API进行base64解码
const arrayBuffer = wx.base64ToArrayBuffer(cleanedBase64);
const uint8Array = new Uint8Array(arrayBuffer);
// 使用TextDecoder解码UTF-8
if (typeof TextDecoder === 'function') {
return new TextDecoder('utf-8').decode(uint8Array);
}
// 备用方案:手动解码UTF-8
let result = '';
let i = 0;
while (i < uint8Array.length) {
let codePoint;
// UTF-8解码逻辑
const byte1 = uint8Array[i++];
if (byte1 < 0x80) {
// 单字节字符
codePoint = byte1;
} else if (byte1 < 0xE0) {
// 双字节字符
const byte2 = uint8Array[i++] & 0x3F;
codePoint = ((byte1 & 0x1F) << 6) | byte2;
} else if (byte1 < 0xF0) {
// 三字节字符
const byte2 = uint8Array[i++] & 0x3F;
const byte3 = uint8Array[i++] & 0x3F;
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
} else {
// 四字节字符
const byte2 = uint8Array[i++] & 0x3F;
const byte3 = uint8Array[i++] & 0x3F;
const byte4 = uint8Array[i++] & 0x3F;
codePoint = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;
}
result += String.fromCodePoint(codePoint);
}
return result;
} catch (e) {
console.error(`解码失败: ${e.message}`);
return '';
}
}