后端返回多个独立 JSON 对象拼接:
{"cpu":[100],"mem":[10]}{"cpu":[110],"mem":[11]}{"cpu":[120],"mem":[12]}{"cpu":[130],"mem":[13]}
前端 $.getJSON 解析失败,因这 不是合法的 JSON 格式(JSON 标准要求单一根值)。
后端循环多次 out.write() 导致流中存在多个 JSON 根对象。$.getJSON 内部调用 JSON.parse(),仅能解析单一 JSON 值。
@ResponseBody
@RequestMapping("/metrics")
public String getMetrics() {
JSONArray jsonArray = new JSONArray(); // net.sf.json.JSONArray
for (int i = 10; i <= 13; i++) {
JSONObject obj = new JSONObject();
obj.put("cpu", new JSONArray().add(i * 10));
obj.put("mem", new JSONArray().add(i));
jsonArray.add(obj);
}
return jsonArray.toString();
// 输出:[{"cpu":[100],"mem":[10]},{"cpu":[110],"mem":[11]},...]
}
$.getJSON("/metrics", function(data) {
// data 直接是数组 [{cpu:[100],mem:[10]}, ...]
$.each(data, function(index, item) {
console.log("CPU:", item.cpu[0], "MEM:", item.mem[0]);
// 更新图表/表格
});
});
若需实时推送多条数据,推荐 SSE:
// 后端 Spring MVC
@RequestMapping(value = "/stream", produces = "text/event-stream")
public SseEmitter streamMetrics() {
SseEmitter emitter = new SseEmitter(60000L);
new Thread(() -> {
try {
for (int i = 10; i <= 13; i++) {
JSONObject obj = new JSONObject();
obj.put("cpu", i * 10);
obj.put("mem", i);
emitter.send(SseEmitter.event().data(obj.toString()));
Thread.sleep(1000);
}
emitter.complete();
} catch (Exception e) {
emitter.completeWithError(e);
}
}).start();
return emitter;
}
// 前端
const evtSource = new EventSource("/stream");
evtSource.onmessage = function(e) {
const data = JSON.parse(e.data);
console.log("Real-time:", data);
};
| 格式 | 示例 | $.getJSON 支持 | 适用场景 |
|---|---|---|---|
| 单对象 | {"cpu":100} | ✅ | 单次查询 |
| 对象数组 | [{"cpu":100},{"cpu":110}] | ✅ | 批量返回、列表展示 |
| 多对象拼接 | {"cpu":100}{"cpu":110} | ❌ | 非法 JSON,不可用 |
| JSON Lines | {"cpu":100}\n{"cpu":110} | ❌ | 日志流、需逐行解析 |
| SSE | data: {"cpu":100}\n\n | 原生 EventSource | 实时推送、长连接 |