Angular 6如何写入并保存assets目录下的JSON文件?
问题分析与解决方案
首先得明确:前端浏览器没有权限直接修改服务器(或本地开发服务器)上的静态资源文件,你用HttpClient.post()请求assets/foods.json本质上是向服务器发送了一个POST请求,但Angular CLI的开发服务器(或者生产环境的服务器)不会处理这个请求来修改静态JSON文件,所以你的写入操作根本没生效,这就是为什么getJson还是拿到原来的数据。
下面分几种场景给你针对性的解决方案:
场景1:仅在浏览器会话中临时存储(无需持久化到服务器)
如果只是需要在用户当前会话中保存数据,刷新页面不丢失(但清除浏览器缓存会丢失),可以用localStorage或者sessionStorage来实现:
修改你的JsonService:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { Food } from './food.model'; // 替换成你的Food模型路径 @Injectable({ providedIn: 'root' }) export class JsonService { private jsonPath = 'assets/foods.json'; private storageKey = 'savedFoods'; constructor(private _http: HttpClient) {} // 获取初始JSON数据 + 本地存储的新增数据 getJson(): Observable<Food[]> { return this._http.get<Food[]>(this.jsonPath).pipe( map(initialFoods => { const savedFoods = JSON.parse(localStorage.getItem(this.storageKey) || '[]'); return [...initialFoods, ...savedFoods]; }) ); } // 保存数据到localStorage postJson(food: Food): Observable<Food> { const savedFoods = JSON.parse(localStorage.getItem(this.storageKey) || '[]'); savedFoods.push(food); localStorage.setItem(this.storageKey, JSON.stringify(savedFoods)); return of(food); // 返回Observable匹配方法签名 } }
这样调用postJson后,getJson会把初始的JSON数据和本地存储的新增数据合并返回,满足你在前端查看更新后数据的需求。
场景2:需要持久化到服务器(永久保存)
如果希望数据真正写入文件、永久保存,必须借助后端服务。这里给你一个简单的Node.js后端示例:
1. 编写Node.js后端接口(基于Express)
const express = require('express'); const fs = require('fs'); const path = require('path'); const cors = require('cors'); const app = express(); app.use(cors()); // 允许跨域请求(解决Angular开发服务器和Node服务器端口不同的问题) app.use(express.json()); // 解析JSON请求体 // 写入JSON文件的接口 app.post('/api/foods', (req, res) => { const food = req.body; const filePath = path.join(__dirname, 'assets', 'foods.json'); // 对应你的JSON文件路径 fs.readFile(filePath, 'utf8', (err, data) => { if (err) return res.status(500).json({ error: '读取文件失败' }); const foods = JSON.parse(data); foods.push(food); fs.writeFile(filePath, JSON.stringify(foods, null, 2), (err) => { if (err) return res.status(500).json({ error: '写入文件失败' }); res.json(food); }); }); }); // 获取JSON数据的接口 app.get('/api/foods', (req, res) => { const filePath = path.join(__dirname, 'assets', 'foods.json'); fs.readFile(filePath, 'utf8', (err, data) => { if (err) return res.status(500).json({ error: '读取文件失败' }); res.json(JSON.parse(data)); }); }); app.listen(3000, () => { console.log('后端服务器运行在 http://localhost:3000'); });
2. 修改Angular服务,调用后端接口
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Food } from './food.model'; @Injectable({ providedIn: 'root' }) export class JsonService { private apiUrl = 'http://localhost:3000/api/foods'; // 后端接口地址 constructor(private _http: HttpClient) {} public postJson(food: Food): Observable<Food> { const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }; return this._http.post<Food>(this.apiUrl, food, httpOptions); } public getJson(): Observable<Food[]> { return this._http.get<Food[]>(this.apiUrl); } }
这样调用postJson后,后端会真正把数据写入foods.json文件,后续getJson就能拿到更新后的数据了。
场景3:Electron桌面应用(如果你的项目是Electron)
如果是Electron桌面应用,因为可以访问Node.js的API,你可以直接用fs模块读写本地文件:
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { Food } from './food.model'; const fs = require('fs'); const path = require('path'); @Injectable({ providedIn: 'root' }) export class JsonService { // Electron中获取assets文件的绝对路径 private jsonPath = path.join(__dirname, '../assets/foods.json'); constructor() {} getJson(): Observable<Food[]> { const data = fs.readFileSync(this.jsonPath, 'utf8'); return of(JSON.parse(data)); } postJson(food: Food): Observable<Food> { const data = fs.readFileSync(this.jsonPath, 'utf8'); const foods = JSON.parse(data); foods.push(food); fs.writeFileSync(this.jsonPath, JSON.stringify(foods, null, 2)); return of(food); } }
注意:这个方案只适用于Electron桌面应用,普通Web浏览器环境下无法使用。
内容的提问来源于stack exchange,提问作者psc37
相关产品推荐
相关产品推荐

