NativeScript 8.3(TypeScript)应用文件下载性能与健壮性优化咨询
NativeScript文件下载功能:性能与健壮性优化建议
针对你的NativeScript 8.3(TypeScript)应用的文件下载功能,结合给定环境(文件大小<200KB、WiFi环境、Express/Node服务端),从性能和健壮性角度给出以下优化建议:
服务端优化(Express路由)
当前代码
const download = (req, res) => { const fileName = req.params.name; res.download(dirRoot + fileName, fileName, (err) => { if (err) { res.status(500).send({message: "Echec téléchargement de fichier. " + err,}); console.log("!!!!!! download, échec envoi du fichier " + dirRoot + fileName); } else console.log(getCurrentDate() + " Envoi réussi du fichier " + dirRoot + fileName); }); };
健壮性优化
- 路径安全校验:直接拼接文件名存在路径遍历风险(如传入
../malicious.csv),用path.resolve限制访问范围:const safePath = path.resolve(dirRoot, fileName); if (!safePath.startsWith(dirRoot)) { return res.status(403).send({message: "Accès refusé"}); } - 文件存在性预检查:提前校验文件是否存在,返回明确的404错误而非通用500:
fs.access(safePath, fs.constants.F_OK, (err) => { if (err) { return res.status(404).send({message: "Fichier non trouvé"}); } res.download(safePath, fileName, ...); }); - 错误信息脱敏:避免向客户端暴露服务器内部细节,仅返回通用提示,详细错误仅记录日志:
if (err) { res.status(500).send({message: "Échec du téléchargement, veuillez réessayer"}); console.error("Erreur envoi fichier", safePath, err); }
性能优化
- 启用静态文件缓存:添加缓存头让客户端缓存文件,减少重复请求:
res.setHeader('Cache-Control', 'public, max-age=86400'); // 缓存1天 res.download(safePath, fileName, ...); - 保持流式传输:
res.download已默认使用流式传输,无需额外修改,这能避免将整个文件加载到内存,适合并发场景。
客户端优化(NativeScript TypeScript)
当前代码
export async function GetStock():Promise<string> { let result = ""; if (global.selfIP != "") { let serverUrl = "http://" + global.serverIP + ":8080/files/stock.csv"; await Http.request({url : serverUrl, method : "GET",}).then( (response: HttpResponse) => { try { if ((response.statusCode >= 200) && (response.statusCode <=304)) { const resultat = response.content.toString(); const chemin : string = path.join(downloadsPath, 'stock.csv') const filefevcsv : File = File.fromPath(chemin); filefevcsv.writeTextSync(resultat, WriteOnError, encoding.UTF_8); } else throw Error("Code réponse du serveur : " + response.statusCode); } catch(err) { result = serverUrl + "\nException traitement requete: " + err.message; } }, (e) => { result = serverUrl + "\nException requete: " + e.message; } ), (error) => { result += serverUrl + "\nErreur requête : " + error; } } else result += "Connexion wifi non établie"; return result; }
健壮性优化
- 统一异步代码风格:移除
await与then/catch的混合使用,改用try/catch包裹await,逻辑更清晰:export async function GetStock(): Promise<string> { if (!global.selfIP) { return "Connexion wifi non établie"; } const serverUrl = `http://${global.serverIP}:8080/files/stock.csv`; try { const response = await Http.request({ url: serverUrl, method: "GET" }); if (!(response.statusCode >= 200 && response.statusCode <= 304)) { throw new Error(`Code réponse du serveur : ${response.statusCode}`); } const resultat = response.content.toString(); const chemin = path.join(downloadsPath, 'stock.csv'); const filefevcsv = File.fromPath(chemin); filefevcsv.writeTextSync(resultat, WriteOnError, encoding.UTF_8); } catch (err: any) { return `${serverUrl}\nException: ${err.message}`; } return ""; } - 添加请求超时:设置超时时间避免请求无限等待:
const response = await Http.request({ url: serverUrl, method: "GET", timeout: 10000 // 10秒超时 }); - 细化文件写入错误:区分网络错误与文件写入错误,提升问题定位效率:
try { const response = await Http.request({ url: serverUrl, method: "GET" }); // ... 状态码校验 const resultat = response.content.toString(); const chemin = path.join(downloadsPath, 'stock.csv'); const filefevcsv = File.fromPath(chemin); try { filefevcsv.writeTextSync(resultat, WriteOnError, encoding.UTF_8); } catch (writeErr) { throw new Error(`Échec écriture fichier : ${writeErr.message}`); } } catch (err: any) { return `${serverUrl}\nErreur: ${err.message}`; } - 校验服务器IP格式:避免构建无效URL:
const ipRegex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (!ipRegex.test(global.serverIP)) { return "Adresse serveur invalide"; }
性能优化
- 异步写入替代同步写入:
writeTextSync会阻塞主线程,改用异步的writeText避免UI卡顿:await filefevcsv.writeText(resultat, WriteOnError, encoding.UTF_8); - 利用304缓存响应:配合服务端的缓存头,当服务器返回304时,直接使用本地缓存文件,无需重复下载写入:
if (response.statusCode === 304) { // 直接使用本地已存在的文件,无需处理 return ""; } // 否则执行下载写入逻辑 - 流式写入优化内存占用:避免将整个文件转为字符串加载到内存,直接将响应内容写入文件(如果NativeScript Http支持):
await response.content.toFile(path.join(downloadsPath, 'stock.csv'));
内容的提问来源于stack exchange,提问作者BenoitB
相关产品推荐
相关产品推荐

