Django流式返回字典时JSON格式失效的解决方法咨询
你遇到的问题很典型——直接yield独立的JSON字典会导致多个JSON对象被无分隔地拼接在一起,而标准JSON要求整个响应只能有一个顶层值(对象或数组),所以第二次及之后的输出会让整个响应变成无效JSON。下面给你几种可行的解决方案:
方案1:使用JSON Lines(NDJSON)格式
JSON Lines是一种专门用于流式JSON的格式,规则很简单:每个JSON对象单独占一行,用换行符分隔。这种格式被很多数据处理工具支持,前端也容易实现逐行解析。
修改你的make_response方法,需要导入json模块,把每个字典序列化为JSON字符串后加上换行符再yield:
import json import time def make_response(self): for _ in range(0,3): some_dict = {"data": "some_data"} yield json.dumps(some_dict) + '\n' time.sleep(1)
然后在视图里更新content_type为更标准的JSON Lines类型:
from django.http import StreamingHttpResponse def flights(request, query): req_obj = Flights.RequestObject(query) return StreamingHttpResponse( req_obj.make_response(), content_type="application/x-ndjson" )
前端处理思路:接收响应流时,按换行符分割每一行,对每行单独做JSON解析即可。
方案2:流式输出合法的JSON数组
如果你希望整个响应是一个标准的JSON数组(前端可以直接用JSON.parse解析),可以通过分步输出数组的结构来实现:先输出左括号[,然后依次输出每个JSON元素(注意元素间用逗号分隔),最后输出右括号]。
修改后的make_response方法:
import json import time def make_response(self): # 先输出数组开头 yield '[' first_item = True for _ in range(0,3): some_dict = {"data": "some_data"} if not first_item: # 非第一个元素前加逗号 yield ',' yield json.dumps(some_dict) first_item = False time.sleep(1) # 输出数组结尾 yield ']'
视图里的content_type保持"application/json"即可,这样整个响应流式输出完成后是一个合法的JSON数组:
[{"data": "some_data"},{"data": "some_data"},{"data": "some_data"}]
优点:前端可以像处理普通JSON响应一样,等整个流接收完成后直接解析;如果需要实时处理,也可以用流式JSON解析器逐步读取内容。
方案3:使用Server-Sent Events(SSE)
如果你的场景是前端需要实时接收服务器推送的消息,可以用SSE——这是HTML5标准的服务器推送技术,专门针对这种流式消息场景设计。
修改make_response方法输出SSE格式的内容:
import json import time def make_response(self): for _ in range(0,3): some_dict = {"data": "some_data"} # SSE格式:data: 内容\n\n yield f'data: {json.dumps(some_dict)}\n\n' time.sleep(1)
视图里设置对应的content_type和响应头:
def flights(request, query): req_obj = Flights.RequestObject(query) response = StreamingHttpResponse(req_obj.make_response()) response['Content-Type'] = 'text/event-stream' response['Cache-Control'] = 'no-cache' # 禁止缓存 response['Connection'] = 'keep-alive' return response
前端处理思路:使用浏览器原生的EventSource对象来接收消息,无需手动处理流解析:
const eventSource = new EventSource('/your-flights-url'); eventSource.onmessage = function(event) { const data = JSON.parse(event.data); console.log(data); };
优点:前端实现简单,自带重连机制,适合实时通知、进度更新等场景。
内容的提问来源于stack exchange,提问作者Rafael Marques

