Flutter向Django POST请求报400错误:请求语法问题排查
我来帮你拆解这个问题,从错误日志到代码细节一步步排查:你用Postman向Django的/account/login/接口发POST请求完全正常,但用Flutter的HttpClient发送Map数据时,不仅出现了406错误,还触发了Bad request syntax ('32')的400错误,而且是在添加request.add(utf8.encode(json.encode(map)))之后出现的。
错误日志分析
先看Django的日志:
[19/May/2020 14:58:13] "POST /account/login/ HTTP/1.1" 406 42
[19/May/2020 14:58:13] code 400, message Bad request syntax ('32')
[19/May/2020 14:58:13] "32" 400 -
- 406错误对应你Django代码里的参数缺失分支(
wrong parameter),说明最初请求的参数没有被Django正确解析 - 后面的400错误(
Bad request syntax ('32'))更关键,这表示Django接收到了格式完全错误的请求内容,甚至不是一个合法的HTTP请求,看起来像是只收到了字符32
问题根源
问题出在Flutter的HttpClient使用方式上:
- 当你用
request.add()添加请求体时,可能没有正确结束请求体的写入,或者HttpClient没有自动帮你设置Content-Length头,导致Django端接收请求时出现解析异常 - 另外,你在函数里硬编码了
map = { "username":"user", "password":"password" };,这会覆盖传入的data参数,这也是一个小问题(不过和当前错误无关,但需要修正)
解决步骤和代码修正
针对HttpClient的请求问题,我们可以做以下调整:
1. 正确设置请求头并确保请求体完整发送
手动计算并设置Content-Length头,同时改用request.write()或者确保add()之后正确关闭请求体写入:
修正后的Flutter代码:
import 'dart:convert'; import 'dart:io'; Future<dynamic> postGoa(String endpoint, Map data) async { // 注意:这里应该使用传入的data,而不是硬编码的map Map map = data; var url = _getUrl("POST", endpoint); var client = HttpClient(); try { HttpClientRequest request = await client.postUrl(Uri.parse(url)); // 设置Content-Type为application/json request.headers.set(HttpHeaders.contentTypeHeader, 'application/json; charset=utf-8'); if (athenticated != null && athenticated.isNotEmpty) { request.headers.set(HttpHeaders.authorizationHeader, 'Bearer ' + athenticated); } // 编码JSON数据 String jsonBody = json.encode(map); // 计算内容长度并设置 request.headers.set(HttpHeaders.contentLengthHeader, utf8.encode(jsonBody).length); // 写入请求体 await request.write(jsonBody); HttpClientResponse response = await request.close(); String mydata = await response.transform(utf8.decoder).join(); return mydata; } catch (e) { // 捕获异常,方便调试 print('请求异常:$e'); return null; } finally { client.close(); } }
2. 更简洁的替代方案(推荐)
如果还是有问题,可以尝试用官方推荐的http包替代HttpClient,代码会更简洁,出错概率更低:
import 'package:http/http.dart' as http; import 'dart:convert'; Future<dynamic> postGoa(String endpoint, Map data) async { var url = Uri.parse(_getUrl("POST", endpoint)); var headers = { 'Content-Type': 'application/json', if (athenticated != null && athenticated.isNotEmpty) 'Authorization': 'Bearer ' + athenticated, }; var response = await http.post(url, headers: headers, body: json.encode(data)); return response.body; }
3. Django端调试优化
虽然Django代码本身没问题,但可以加个日志打印request.body,方便调试时查看Flutter发送的原始请求内容:
@api_view(['POST']) def login_user(request): print("原始请求体:", request.body) # 添加这行调试代码 print(request.data) # 后续代码不变...
这样你就能看到Flutter发送的内容到底是什么,更容易定位问题。
内容的提问来源于stack exchange,提问作者Mohsen Haydari

