Django+Ngrok环境下JS前端POST请求异常及跨网连接失败问题
问题描述
我用Python Django开发Web服务,部署前用Ngrok做测试,遇到三个问题:
- 前端JS发送的POST请求在部分接口拿不到数据,返回None,Django日志和浏览器都显示响应200 OK,但日志里没数据输出
- 跨网访问时所有请求都报CONNECTION_REFUSED错误
- 表单提交的POST请求正常,但JS发的不行,已经按文档配置corsheaders中间件但没用
JS POST请求代码
const url = "http://localhost:8000/register_equipment/"; const data = { "product": inputProduct.value, "description": inputDescription.value, "serial": inputSerial.value, "warehouse_location": inputWarehouseLocation.value, "shelf_location": inputShelfLocation.value, "additional_location": inputAdditionalLocation.value, "observations": inputObservations.value, "quantity": inputQuantity.value, "dedicated": dedicatedValues }; // Request configuration const options = { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCookie('csrftoken') // Add CSRF token header }, body: JSON.stringify(data) }; // Perform the request using fetch fetch(url, options) .then(response => { if (response.ok) { return response.json(); // Convert the response to JSON } throw new Error('Request failed'); }) .then(responseData => { console.log(responseData.groups); // Handle response data }) .catch(error => { console.error('Error fetching group list:', error); // Handle errors });
获取CSRF Token的函数
function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
Django视图代码
@csrf_exempt def register_equipment(request): if not request.user.is_authenticated: return redirect('login') if request.method == 'POST': # Get JSON data from the frontend data = json.loads(request.body) print(data) print(data.get("dedicated")) # Process location data location = { "warehouse": data.get("warehouse_location"), "shelf": data.get("shelf_location"), "additional": data.get("additional_location"), } # Process incoming data and save the equipment try: new_equipment = Equipment( product=data.get("product"), description=data.get("description"), serial=data.get("serial"), location=location, observations=data.get("observations"), dedicated=data.get("dedicated"), quantity=data.get("quantity"), available=True ) new_equipment.save() response_data = {'message': 'Equipment registered successfully'} return JsonResponse(response_data) except KeyError: return JsonResponse({'error': 'Missing required data'}, status=400) return JsonResponse({'error': 'Failed to register equipment'}, status=400)
CORS配置
INSTALLED_APPS = [ ... "corsheaders", ... ] MIDDLEWARE = [ ... "corsheaders.middleware.CorsMiddleware", ... ]
正常工作的表单代码
<form method="post"> {% csrf_token %} <div class="form-group"> <label for="username">Nombre de usuario:</label> <input type="text" class="form-control" name="username" id="username" required> </div> <div class="form-group"> <label for="password">Contraseña:</label> <input type="password" class="form-control" name="password" id="password" required> </div> <button type="submit" class="btn btn-primary btn-block">Iniciar sesión</button> </form>
解决方案
问题1:JS POST请求返回None,日志无数据输出
- 排查前端输入值:在
fetch前添加console.log(data),确认inputProduct.value等DOM元素是否正确获取、字段值是否为空。如果某个输入元素未找到,对应字段会是undefined,JSON序列化后变成null。 - 完善视图异常捕获:当前仅捕获
KeyError,但json.loads(request.body)可能抛出JSONDecodeError(比如前端JSON格式错误),导致打印逻辑被跳过。修改视图代码:
from django.http import JsonResponse import json from json.decoder import JSONDecodeError @csrf_exempt def register_equipment(request): if not request.user.is_authenticated: return redirect('login') if request.method == 'POST': try: data = json.loads(request.body) print(data) print(data.get("dedicated")) location = { "warehouse": data.get("warehouse_location"), "shelf": data.get("shelf_location"), "additional": data.get("additional_location"), } new_equipment = Equipment( product=data.get("product"), description=data.get("description"), serial=data.get("serial"), location=location, observations=data.get("observations"), dedicated=data.get("dedicated"), quantity=data.get("quantity"), available=True ) new_equipment.save() response_data = {'message': 'Equipment registered successfully'} return JsonResponse(response_data) except JSONDecodeError: return JsonResponse({'error': 'Invalid JSON format'}, status=400) except KeyError as e: return JsonResponse({'error': f'Missing required data: {str(e)}'}, status=400) return JsonResponse({'error': 'Failed to register equipment'}, status=400)
- 检查
dedicatedValues类型:如果是数组或复杂对象,确认Django的Equipment模型中dedicated字段是否为JSONField,否则无法正常存储。
问题2:跨网访问报CONNECTION_REFUSED错误
- 替换请求URL:前端必须使用Ngrok提供的公网域名,比如Ngrok生成的
https://abc123.ngrok.io,将JS中的url改为"https://abc123.ngrok.io/register_equipment/"。 - 允许Django服务外部访问:启动开发服务器时执行
python manage.py runserver 0.0.0.0:8000,默认的localhost:8000仅允许本地访问,Ngrok无法转发请求。
问题3:JS POST请求无效,CORS配置不生效
- 完善CORS配置:在
settings.py中补充以下配置:
# 测试环境可临时允许所有域名,生产环境需指定具体域名 CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_CREDENTIALS = True # 生产环境示例: # CORS_ALLOWED_ORIGINS = [ # "https://your-ngrok-domain.ngrok.io", # "http://localhost:3000", # ]
- 调整中间件顺序:
CorsMiddleware必须放在CommonMiddleware之前,否则CORS头无法正确设置:
MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", # 其他中间件... ]
- 优化CSRF Cookie设置:使用Ngrok的HTTPS时,需在
settings.py中添加:
CSRF_COOKIE_SAMESITE = 'Lax' SESSION_COOKIE_SAMESITE = 'Lax' CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True
- 生产环境建议移除
@csrf_exempt,确保CSRF保护生效。
内容的提问来源于stack exchange,提问作者mrdonbello
相关产品推荐
相关产品推荐

