Angular调用NestJS下载路由器配置文件时Http解析失败求助
问题背景
用Angular做前端、NestJS做后端开发路由器配置工具,目标是通过Web界面简化Cisco、Juniper等设备的配置流程——后端处理所有计算逻辑,前端只需选设备、填配置信息(名称、接口配置等)就能生成可上传至设备的配置脚本。
当前遇到的问题:前端发送GET请求获取配置文件时,后端返回200状态码且响应体包含配置内容,但前端控制台抛出HTTP解析错误。
前端Angular服务代码
generateConfigFile() { return this.http.get(`${this.API_BASE_LINK}/cisco/getScript`); }
后端NestJS控制器代码
@Get('getScript') downloadConfigFile(@Res() res : Response) { let fileContent: string; let filename: string; const result = this.ciscoConfigExtractorService.downloadConfigFile(); fileContent = result.fileContent; filename = result.filename; const filepath = path.join(path.join(process.cwd(), 'files'), filename); fs.writeFile(filepath, fileContent, (err) => { if (err) { console.error(err); res.status(500).send('Failed to save file.'); return; } // Return the file to the user res.contentType('text/plain'); res.download(filepath, fileContent); }); }
前端错误信息
{ "headers": { "normalizedNames": {}, "lazyUpdate": null }, "status": 200, "statusText": "OK", "url": "http://localhost:3000/cisco/getScript", "ok": false, "name": "HttpErrorResponse", "message": "Http failure during parsing for http://localhost:3000/cisco/getScript", "error": { "error": {}, "text": "\n!\nversion 12.2\nno service timestamps log datetime msec\nno service timestamps debug datetime msec\n service password-encryption\n!\nhostname R1\n!\n!\n!\n!\n!\n!\n!\n!\nip cef\nno ipv6 cef\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n ip domain-lookup\n!\n!\n!\n!\n!\n!\n!\n!\n!\ninterface FastEthernet0/0\n \n ip address 41.1.1.14 255.255.255.252\n \n auto\n auto\n clock rate -1\n \n,!\ninterface FastEthernet1/0\n \n ip address 192.168.25.97 255.255.255.224\n \n auto\n auto\n clock rate -1\n \n,!\ninterface Serial2/0\n \n ip address 192.168.25.129 255.255.255.252\n \n \n \n clock rate 64000\n \n,!\ninterface Serial3/0\n \n ip address 192.168.25.137 255.255.255.252\n ipv6 address 2001:db8:acad::1/64\n \n \n clock rate 64000\n \n,!\ninterface FastEthernet4/0\n no ip address\n \n \n \n \n clock rate -1\n shutdown\n,!\ninterface FastEthernet5/0\n no ip address\n \n \n \n \n clock rate -1\n shutdown\n,!\ninterface FastEthernet0/0\n \n ip address 41.1.1.14 255.255.255.252\n \n auto\n auto\n clock rate -1\n \n,!\ninterface FastEthernet1/0\n \n ip address 192.168.25.97 255.255.255.224\n \n auto\n auto\n clock rate -1\n \n,!\ninterface Serial2/0\n \n ip address 192.168.25.129 255.255.255.252\n \n \n \n clock rate 64000\n \n,!\ninterface Serial3/0\n \n ip address 192.168.25.137 255.255.255.252\n ipv6 address 2001:db8:acad::1/64\n \n \n clock rate 64000\n \n,!\ninterface FastEthernet4/0\n no ip address\n \n \n \n \n clock rate -1\n shutdown\n,!\ninterface FastEthernet5/0\n no ip address\n \n \n \n \n clock rate -1\n shutdown\n\nip classless\n\nip route 192.168.25.64 255.255.255.224 FastEthernet0/0 192.168.25.138 1\n,\nip route 192.168.25.0 255.255.255.192 192.168.25.130 1\n,\nip route 192.168.25.64 255.255.255.224 192.168.25.130 5\n,\nip route 192.168.25.0 255.255.255.192 192.168.25.138 5\n,\nip route 0.0.0.0 0.0.0.0 41.1.1.13 1\n,\nipv6 route 2001:db8:acad::1/64 Fa0/0 1\n,\nip route 192.168.25.64 255.255.255.224 FastEthernet0/0 192.168.25.138 1\n,\nip route 192.168.25.0 255.255.255.192 192.168.25.130 1\n,\nip route 192.168.25.64 255.255.255.224 192.168.25.130 5\n,\nip route 192.168.25.0 255.255.255.192 192.168.25.138 5\n,\nip route 0.0.0.0 0.0.0.0 41.1.1.13 1\n,\nipv6 route 2001:db8:acad::1/64 Fa0/0 1\n\n!\nip flow-export version 9\n!\n!\n!\n!\n!\n!\n!\n!\nline con 0\n!\nline aux 0\n!\nline vty 0 4\n login\n!\n!\n!\n" } }
解决方案
1. 前端修改:指定响应类型为文本
Angular的HttpClient.get默认会尝试将响应解析为JSON,而返回的是纯文本配置,必须显式指定响应类型为'text':
generateConfigFile() { return this.http.get(`${this.API_BASE_LINK}/cisco/getScript`, { responseType: 'text' }); }
2. 后端修复:修正res.download参数错误
后端代码中res.download(filepath, fileContent)的第二个参数应为文件名,而非文件内容,参数传错会导致响应头异常:
// 错误写法 res.download(filepath, fileContent); // 正确写法 res.download(filepath, filename);
3. 可选优化:后端直接返回内容,跳过本地文件写入
如果不需要在服务器保存配置文件,直接返回文本内容更高效,避免不必要的文件IO操作:
@Get('getScript') downloadConfigFile(@Res() res: Response) { const result = this.ciscoConfigExtractorService.downloadConfigFile(); res.setHeader('Content-Disposition', `attachment; filename="${result.filename}"`); res.contentType('text/plain'); res.send(result.fileContent); }
4. 前端实现浏览器自动下载(可选)
如果需要让浏览器直接触发文件下载,前端拿到文本后可通过Blob实现:
this.configService.generateConfigFile().subscribe({ next: (content) => { const blob = new Blob([content], { type: 'text/plain' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'router-config.txt'; // 也可从后端响应头中获取实际文件名 document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }, error: (err) => console.error('下载失败:', err) });
内容的提问来源于stack exchange,提问作者ABDESSELEM BORHANE EDDINE BOUB
相关产品推荐
相关产品推荐

