You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter项目Nginx切换HTTPS后报Unexpected token < JSON解析错误

问题背景

项目后端采用Django、前端采用Flutter开发,HTTP协议下全功能运行正常,将Nginx代理从HTTP切换为HTTPS后,大部分功能可正常使用,仅当数据表无数据、后端需要返回空列表的场景下抛出如下错误:

GET https://servername/project-name/api/commitments/?email=emailaddress%40companyname.de&jahr=2022&kunde=adac-ev 500
FormatException: SyntaxError: Unexpected token < in JSON at position 1

该报错的核心原因是接口未返回合法JSON格式内容,实际返回了以<开头的HTML内容(通常为Nginx错误页、Django异常页或鉴权跳转页),并非Flutter端JSON解析逻辑故障。

对应Flutter端请求实现代码如下:

var uri = (APIPROTOCOL == 'http://')
      ? Uri.http(APIHOST, '/api/commitments/', uriQuery)
      : Uri.https(APIHOST, '$APIHOST_PREFIX/api/commitments/', uriQuery);
try {
   final response = await http.get(
    uri,
    headers: {"Authorization": "Bearer $authToken"},
  );

该问题在本地localhost环境、HTTP协议服务器环境下均无法复现,仅在HTTPS配置的服务器上触发。

服务器端调试方法
  • 直接抓取接口原始响应:跳过Flutter客户端,使用curl或Postman构造和客户端完全一致的请求(携带相同Authorization请求头、查询参数)请求目标HTTPS接口,查看返回的完整响应内容,绝大多数场景下可直接定位返回的是Nginx错误页、Django调试页还是拦截跳转页。curl调试命令参考:
    curl -v -H "Authorization: Bearer 实际业务token值" "https://servername/project-name/api/commitments/?email=emailaddress%40companyname.de&jahr=2022&kunde=adac-ev"
    
  • 排查Nginx运行日志:Nginx错误日志默认存储路径为/var/log/nginx/error.log,定位报错时间点对应的日志条目,可直接确认故障原因是代理超时、请求头大小超限、上游服务返回异常还是location路径匹配错误。
  • 排查Django服务日志:如果使用uWSGI/Gunicorn托管Django服务,直接查看对应服务的运行日志,重点排查空列表查询场景下的异常栈。HTTPS切换后常见触发原因包括:Django配置中SECURE_SSL_REDIRECT、CSRF_TRUSTED_ORIGINS未添加HTTPS域名;空列表响应时响应头被Nginx的gzip、内容替换规则篡改;子路径代理规则在空响应场景下匹配错误,返回了站点默认index.html页面(这也是响应内容以<开头的最常见原因)。
  • 测试环境临时开启Django DEBUG模式(生产环境禁止长期开启):直接访问目标接口,Django调试页会展示完整异常调用栈,可快速定位是否为空列表序列化逻辑问题——比如序列化器在空值场景下读取了不存在的字段,HTTP环境下因代理未修改响应头未触发分支,HTTPS环境下代理添加HSTS等安全头后触发异常逻辑。
本地HTTPS调试环境搭建方案

可完全模拟线上https://servername/project-name/的访问形式,无需采购公网证书,使用本地自签证书即可:

  • 生成本地受信任自签证书:使用本地证书生成工具生成本地域名的SSL证书,初始化本地根证书信任链后,为自定义本地测试域名(可任意命名,比如local.test,不建议使用localhost)生成证书和私钥文件。
  • 修改本地hosts映射:将自定义测试域名指向本地回环地址127.0.0.1,Windows系统hosts路径为C:\Windows\System32\drivers\etc\hosts,Mac/Linux系统路径为/etc/hosts,添加如下映射规则:
    127.0.0.1 local.test
    
  • 配置本地Nginx反向代理:保持和线上Nginx配置逻辑一致,配置HTTPS监听端口、证书路径、子路径代理规则,将/project-name/路径的请求转发到本地运行的Django服务(比如本地Django默认运行在8000端口),核心配置参考:
    server {
        listen 443 ssl;
        server_name local.test;
        # 替换为本地生成的证书实际存储路径
        ssl_certificate /path/to/local.test.pem;
        ssl_certificate_key /path/to/local.test-key.pem;
    
        location /project-name/ {
            # 转发到本地Django服务,路径重写规则和线上保持一致
            proxy_pass http://127.0.0.1:8000/;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            # 以上三个请求头是Django正确识别HTTPS协议的关键配置,缺失会导致Django生成的内部链接仍为HTTP协议
        }
    }
    
  • 调整Django本地配置:将测试域名local.test添加到ALLOWED_HOSTS列表,若开启了SSL相关安全配置,需将https://local.test添加到CSRF_TRUSTED_ORIGINS列表,正常启动Django服务即可。
  • 调整Flutter本地调试配置:将APIPROTOCOL参数设为https://,APIHOST参数设为local.test,APIHOST_PREFIX参数设为/project-name,即可和线上环境保持同协议、同路径调试。如果使用安卓模拟器调试,需将自签证书添加到安卓系统信任证书列表,调试阶段也可临时关闭HTTP客户端的证书校验(仅可用于本地调试,上线前必须恢复校验逻辑)。
  • 轻量调试方案:如果不需要模拟Nginx代理规则,可直接为Django安装SSL服务扩展,使用Django自带的HTTPS启动命令加载自签证书运行服务,配合hosts映射即可快速搭建HTTPS调试环境,适合快速排查Django本身的逻辑问题。

内容的提问来源于stack exchange,提问作者Davood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:06:14