<head><title>413 Request Entity Too Large</title></head> <body> <center><h1>413 Request Entity Too L

博客指出上传文件大小超出 Nginx 允许最大值(默认 1M)是问题原因,并给出解决方法的参考链接 https://blog.youkuaiyun.com/testcs_dn/article/details/78366272 。
GitHub的bilinote项目INFO: 172.18.0.4:58712 - "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.0" 200 OK INFO: 172.18.0.4:58916 - "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.0" 200 OK nginx 172.18.0.1 - - [25/Sep/2025:13:27:55 +0000] "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.1" 200 120 "http://localhost:3015/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0" "-" backend INFO: 172.18.0.4:58924 - "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.0" 200 OK nginx 172.18.0.1 - - [25/Sep/2025:13:27:58 +0000] "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.1" 200 120 "http://localhost:3015/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0" "-" backend 2025-09-25 13:27:59 [ERROR] app.services.note - ❌ 总结内容失败,task_id=2c0fd551-f831-4d31-81a9-19d10a4aefce,错误信息:<html> <head><title>413 Request Entity Too Large</title></head> <body> <center><h1>413 Request Entity Too Large</h1></center> <hr><center>openresty</center> </body> </html> 2025-09-25 13:27:59 [ERROR] app.services.note - ❌ 笔记生成流程异常终止,task_id=2c0fd551-f831-4d31-81a9-19d10a4aefce,错误信息:<html> <head><title>413 Request Entity Too Large</title></head> <body> <center><h1>413 Request Entity Too Large</h1></center> <hr><center>openresty</center> </body> </html> nginx 172.18.0.1 - - [25/Sep/2025:13:28:00 +0000] "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.1" 200 223 "http://localhost:3015/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0" "-" backend INFO: 172.18.0.4:58936 - "GET /api/task_status/2c0fd551-f831-4d31-81a9-19d10a4aefce HTTP/1.0" 200 OK
09-26
{ "inputs": { "image": { "type": "image", "transfer_method": "local_file", "upload_file_id": "2d6beca7-cf33-430b-b261-ae54d5bf72bd" } }, "response_mode": "blocking", "user": "apifox-test" }等一等,你的这部分在哪里,这部分没有啊,然后下面是我改完的代码 // IndexPage.ets import http from '@ohos.net.http'; import fs from '@ohos.file.fs'; import util from '@ohos.util'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { promptAction } from '@kit.ArkUI'; import { common } from '@kit.AbilityKit'; import { parseAnswer, Segment } from './Parser'; // ======== 明确定义所有接口 ======== interface Msg { isMe: boolean; text: string; } interface UploadResponse { id: string; url: string; mime_type: string; size: number; } interface FileInput { type: 'document'; transfer_method: 'local_file'; upload_file_id: string; } interface GeneratedTypeLiteralInterface_1 { file1: FileInput; } interface AiPayloadWithFile { inputs: GeneratedTypeLiteralInterface_1; response_mode: 'blocking'; user: string; } interface TextInput { input: string; } interface AiPayload { inputs: TextInput; response_mode: 'blocking'; user: string; } interface OutputText { text?: string; } interface WorkflowOutputs { outputs?: OutputText; } interface AiResponse { data?: WorkflowOutputs; } @Component struct ThinkFold { @Prop content: string = '' @State folded: boolean = true build() { Column() { Row() { Text('思考内容').fontColor('#909399').fontSize(12) Blank() Text(this.folded ? '展开' : '收起').fontColor('#07C160').fontSize(12) } .width('100%') .onClick(() => this.folded = !this.folded) if (!this.folded) { Text(this.content) .fontSize(14).fontColor('#737373') .padding(8).backgroundColor('#F3F4F6').borderRadius(4) .width('100%') } } .padding(8).backgroundColor('#FAFAFA').borderRadius(0).width('100%') } } @Component struct CodeBlock { @Prop code: string = '' private copy() { promptAction.showToast({ message: '已复制', duration: 800 }) } build() { Column() { Stack() { Text(this.code) .fontSize(13).fontFamily('monospace') .padding(12).backgroundColor('#1e1e1e').fontColor('#d4d4d4') .borderRadius(6).maxLines(10).width('100%') Row() { Blank() Text('复制') .fontColor(Color.White).fontSize(11) .backgroundColor('#00000000') .padding({ top: 2, bottom: 2, left: 6, right: 6 }) .borderRadius(4) .onClick(() => this.copy()) }.width('100%').padding({ top: 6, right: 8 }) }.width('100%') } .width('100%') .alignItems(HorizontalAlign.Start) } } interface GeneratedObjectLiteralInterface_1 { 'Content-Type': string; 'Authorization': string; } @Entry @Component struct IndexPage { @State status: number = 0; @State msgList: Msg[] = []; @State input: string = ''; @State imgUrl: string = ''; @State showPreview: boolean = false; // ======== 上传图片文件 ======== private async uploadImage(uri: string): Promise<string | null> { const httpReq = http.createHttp(); try { // 使用 fs.open 打开文件 const file = await fs.open(uri, fs.OpenMode.READ_ONLY); if (file.fd === null) { promptAction.showToast({ message: '无法打开图片', duration: 2000 }); return null; } const boundary = 'Boundary-' + Date.now().toString(16); const headers: GeneratedObjectLiteralInterface_1 = { 'Content-Type': `multipart/form-data; boundary=${boundary}`, 'Authorization': 'Bearer app-Gea9C0drsp7kL14kIpxzzpSL' }; const fileName = `image_${Date.now()}.jpg`; const fileType = 'image/jpeg'; let bodyParts: Uint8Array[] = []; // 构造 form-data 头部 const fileHeader = `--${boundary}\r\n` + `Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n` + `Content-Type: ${fileType}\r\n\r\n`; bodyParts.push(new util.TextEncoder().encode(fileHeader)); // 读取文件流 const chunkSize = 64 * 1024; let totalBytesRead = 0; let fileData = new Uint8Array(0); while (true) { const buffer = new ArrayBuffer(chunkSize); const bytesRead = await fs.read(file.fd, buffer); if (bytesRead <= 0) break; const chunk = new Uint8Array(buffer.slice(0, bytesRead)); const newBuffer = new Uint8Array(fileData.length + chunk.length); newBuffer.set(fileData); newBuffer.set(chunk, fileData.length); fileData = newBuffer; totalBytesRead += bytesRead; } bodyParts.push(fileData); await fs.close(file.fd); // 添加结尾 const footer = `\r\n--${boundary}--\r\n`; bodyParts.push(new util.TextEncoder().encode(footer)); const requestBody = this.concatUint8Arrays(bodyParts); // 发起请求 const uploadRes = await httpReq.request('http://192.168.52.35/v1/files/upload', { method: http.RequestMethod.POST, header: headers, extraData: requestBody }); if (uploadRes.responseCode === 201) { const result = JSON.parse(uploadRes.result as string) as UploadResponse; return result.id; } else { console.error(`上传失败: ${uploadRes.responseCode}, ${uploadRes.result}`); return null; } } catch (err) { console.error(`上传异常: ${JSON.stringify(err)}`); return null; } finally { httpReq.destroy(); } } // 合并 Uint8Array 工具函数 private concatUint8Arrays(arrays: Uint8Array[]): Uint8Array { let totalLength = arrays.reduce((acc, arr) => acc + arr.length, 0); let result = new Uint8Array(totalLength); let offset = 0; for (let arr of arrays) { result.set(arr, offset); offset += arr.length; } return result; } // ======== 调用 AI(文本)======== private async callAi(question: string): Promise<string> { const httpReq = http.createHttp(); try { const res = await httpReq.request( 'http://192.168.52.35/v1/workflows/run', { method: http.RequestMethod.POST, header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer app-kaBVlNbOwaTeCEf6LutPEVNQ' }, extraData: JSON.stringify({ inputs: { input: question }, response_mode: 'blocking', user: 'admin' } as AiPayload) // 使用类型断言 } ); if (res.responseCode === 200) { const json: AiResponse = JSON.parse(res.result as string); return json.data?.outputs?.text ?? 'AI 没返回内容'; } return `请求失败 ${res.responseCode}`; } catch (err) { return `网络错误 ${err}`; } finally { httpReq.destroy(); } } // ======== 调用 AI(带文件 ID)======== private async callAiWithFile(fileId: string): Promise<string> { const httpReq = http.createHttp(); try { const res = await httpReq.request( 'http://192.168.52.35/v1/workflows/run', { method: http.RequestMethod.POST, header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer app-kaBVlNbOwaTeCEf6LutPEVNQ' }, extraData: JSON.stringify({ inputs: { file1: { type: 'document', transfer_method: 'local_file', upload_file_id: fileId } }, response_mode: 'blocking', user: 'admin' } as AiPayloadWithFile) // 使用类型断言 } ); if (res.responseCode === 200) { const json: AiResponse = JSON.parse(res.result as string); return json.data?.outputs?.text ?? 'AI 没返回内容'; } return `请求失败 ${res.responseCode}`; } catch (err) { return `网络错误 ${err}`; } finally { httpReq.destroy(); } } // ======== 发送消息主逻辑 ======== private async send() { // 场景一:有图片要发送 if (this.showPreview && this.imgUrl) { this.status = 1; const fileId = await this.uploadImage(this.imgUrl); if (!fileId) { this.status = 0; promptAction.showToast({ message: '图片上传失败', duration: 2000 }); return; } // 清除预览 this.showPreview = false; this.imgUrl = ''; // 添加"正在分析" this.msgList.push({ isMe: false, text: '正在分析图片...' }); const thinkingIndex = this.msgList.length - 1; try { const ans = await this.callAiWithFile(fileId); this.msgList[thinkingIndex] = { isMe: false, text: ans }; } catch (e) { this.msgList[thinkingIndex] = { isMe: false, text: `分析失败: ${e}` }; } finally { this.status = 0; } return; } // 场景二:普通文本提问 const q = this.input.trim(); if (!q || this.status !== 0) return; this.msgList.push({ isMe: true, text: q }); this.input = ''; const thinkingIndex = this.msgList.length; this.msgList.push({ isMe: false, text: '思考中...' }); this.status = 1; try { const ans = await this.callAi(q); this.msgList[thinkingIndex] = { isMe: false, text: ans }; } catch (e) { this.msgList[thinkingIndex] = { isMe: false, text: `出错:${e}` }; } finally { this.status = 0; } } // ======== 打开图库选择器 ======== async selectPhoto() { try { const picker = new photoAccessHelper.PhotoViewPicker(); const selectResult = await picker.select({ MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE, maxSelectNumber: 1 }); if (selectResult.photoUris && selectResult.photoUris.length > 0) { this.imgUrl = selectResult.photoUris[0]; this.showPreview = true; } } catch (err) { console.error(`选择图片失败: ${JSON.stringify(err)}`); promptAction.showToast({ message: '选择图片失败', duration: 2000 }); } } // ======== UI 构建 ======== build() { Column() { /* 标题栏 */ Row() { Text('鸿蒙 AI 小助手') .fontSize(18) .fontColor('#000000') .fontWeight(FontWeight.Medium) } .width('100%') .height(52) .backgroundColor('#FFFFFF') .justifyContent(FlexAlign.Center) .border({ width: { bottom: 1 }, color: '#F0F0F0' }) /* 聊天列表 */ List({ space: 12 }) { ForEach(this.msgList, (item: Msg) => { ListItem() { Row() { if (item.isMe) { Text(item.text) .backgroundColor('#07C160') .fontColor('#FFFFFF') .padding({ top: 10, bottom: 10, left: 14, right: 14 }) .borderRadius(10) .fontSize(15) } else { Column() { ForEach(parseAnswer(item.text), (seg: Segment) => { if (seg.type === 'think') { ThinkFold({ content: seg.content }) } else if (seg.type === 'code') { CodeBlock({ code: seg.content }) } else { Text(seg.content) .backgroundColor('#FFFFFF') .fontColor('#2C2C2C') .padding({ top: 10, bottom: 10, left: 14, right: 14 }) .borderRadius(10) .fontSize(15) .border({ width: 1, color: '#E9E9E9' }) } }, (seg: Segment) => seg.type + seg.content.slice(0, 20)) } } } .width('100%') .justifyContent(item.isMe ? FlexAlign.End : FlexAlign.Start) .padding({ left: 16, right: 16 }) } }, (item: Msg) => item.text + item.isMe) } .width('100%') .height('100%') .layoutWeight(1) .backgroundColor('#F7F7F7') .padding({ top: 8 }) /* 图片预览栏 */ if (this.showPreview && this.imgUrl) { Row() { Image(this.imgUrl) .width(60).height(60).borderRadius(8).objectFit(ImageFit.Cover) Blank(8) Text('发送此图片').fontSize(14).fontColor('#909399') Blank() Text('✕') .fontSize(18).fontColor('#666') .onClick(() => { this.imgUrl = ''; this.showPreview = false; }) } .background(Color.White) .width('100%') .padding({ left: 16, right: 16, top: 8, bottom: 8 }) } /* 底部输入栏 */ Row() { TextInput({ placeholder: '输入问题…', text: $$this.input }) .layoutWeight(1) .height(48) .backgroundColor('#FFFFFF') .borderRadius(24) .padding({ left: 18, right: 18 }) .fontSize(16) .border({ width: 1, color: '#E0E0E0' }) Blank(10) Image($r('app.media.photo')) .width(38) .height(38) .onClick(() => this.selectPhoto()) Blank(10) if (this.status === 0) { Button('发送') .width(76) .height(38) .backgroundColor('#07C160') .borderRadius(19) .fontSize(14) .fontColor('#FFFFFF') .onClick(() => this.send()) } else { LoadingProgress().width(50).height(50).color(Color.Gray) } } .width('100%') .padding(12) .backgroundColor('#FFFFFF') .border({ width: { top: 1 }, color: '#F0F0F0' }) } .width('100%') .height('100%') .backgroundColor('#FFFFFF') } } 11-27 20:01:25.970 29682-29682 A03d00/JSAPP com.example.aitext E 上传失败: 413, <html> <head><title>413 Request Entity Too Large</title></head> <body> <center><h1>413 Request Entity Too Large</h1></center> <hr><center>nginx/1.27.5</center> </body> </html> 现在报错413
最新发布
11-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值