You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:57:09