Django+React电商网站JWT授权:前端Fetch获取Token报错求助
问题场景
我正在用Django、Django REST API和React搭建电商网站,采用Rest Framework Simple JWT实现授权功能,自定义了MyTokenObtainPairView用于获取携带用户数据的Token。后端配置、视图、URL均正常,但前端登录时通过Fetch请求获取Token失败,报错信息:TypeError: Failed to execute 'fetch' on 'Window': Invalid name。
相关代码如下:
后端代码
Settings.py
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ) } SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), 'REFRESH_TOKEN_LIFETIME': timedelta(days=90), 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, 'UPDATE_LAST_LOGIN': False, 'ALGORITHM': 'HS256', 'VERIFYING_KEY': None, 'AUDIENCE': None, 'ISSUER': None, 'JWK_URL': None, 'LEEWAY': 0, 'AUTH_HEADER_TYPES': ('Bearer',), 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', 'USER_ID_FIELD': 'id', 'USER_ID_CLAIM': 'user_id', 'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule', 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), 'TOKEN_TYPE_CLAIM': 'token_type', 'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser', 'JTI_CLAIM': 'jti', 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5), 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), }
Views.py
from rest_framework.response import Response from rest_framework.decorators import api_view from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView class MyTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) # Add custom claims token['username'] = user.username # ... return token class MyTokenObtainPairView(TokenObtainPairView): serializer_class = MyTokenObtainPairSerializer @api_view(['GET','POST']) def getRoutes(request): routes = [ '/api/token', '/api/refresh', ] return Response(routes)
Urls.py
from . import views from .views import * from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, ) urlpatterns = [ path('',views.getRoutes,name='get_routes'), path('token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'), path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), ]
前端代码
React逻辑
const [username,setUsername] = useState('') const [password,setPassword] = useState('') const loginUser = async (e)=>{ e.preventDefault() try { let response = await fetch('http://127.0.0.1:8000/api/token/',{ method:'POST', headers:{ 'Content-Type:':'application/json', }, body:JSON.stringify({'username':e.target.username.value,'password':e.target.password.value}) // tried to use useState variables to hold the value & send it through body of fetch! }) const data = await response.json() setAuthTokens(data) } catch (error) { console.log("failed:",error) } }
登录表单
<form className="form" onSubmit={loginUser}> <h5>Username:</h5> <input type="text" value={username} name='username' onChange={(e)=>setUsername(e.target.value)} /> <h5>Password:</h5> <input type="password" value={password} name='password' onChange={(e)=>setPassword(e.target.value)} /> <button className="login-btn" type='submit'>Sign-in</button> <p className="terms">By continuing, you agree to Amazon's Conditions of Use and Privacy Notice.</p> <div className="new-acc"> <p className='new'>New to Amazon?</p> <hr /> <br /> <button className="create-btn">Create Your Amazon Account</button> </div> </form>
错误原因分析
- Header键名错误:报错
Invalid name的直接原因是Fetch请求的headers中Content-Type键名多了一个结尾冒号(写成了'Content-Type:'),浏览器无法识别非法的Header字段名,从而抛出错误。 - 冗余的DOM依赖:已经通过useState维护了
username和password状态,却仍使用e.target.username.value获取值,既冗余又容易引发DOM引用问题。 - 潜在跨域问题:React默认端口3000与Django默认端口8000属于跨域请求,即使修复Header问题,后续可能出现CORS拦截错误。
修复步骤
1. 修正Header键名
将'Content-Type:'改为合法的'Content-Type':
headers:{ 'Content-Type':'application/json', },
2. 使用状态变量传递请求体
直接用已维护的状态变量替代DOM元素取值,代码更简洁可靠:
body:JSON.stringify({'username': username, 'password': password})
修正后的完整loginUser函数:
const loginUser = async (e)=>{ e.preventDefault() try { let response = await fetch('http://127.0.0.1:8000/api/token/',{ method:'POST', headers:{ 'Content-Type':'application/json', }, body:JSON.stringify({'username': username, 'password': password}) }) const data = await response.json() setAuthTokens(data) } catch (error) { console.log("failed:",error) } }
3. 解决跨域问题(必做)
在Django中安装并配置django-cors-headers:
- 安装依赖:
pip install django-cors-headers - 修改
settings.py配置:
INSTALLED_APPS = [ # ... 其他已安装应用 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # ... 其他中间件 ] # 开发环境允许所有跨域请求(生产环境建议指定具体域名) CORS_ALLOW_ALL_ORIGINS = True
验证修复
重启Django服务与React开发服务器,重新提交登录表单,此时应能正常获取JWT Token并存储到authTokens状态中。
内容的提问来源于stack exchange,提问作者Naimur Sharon
相关产品推荐
相关产品推荐

