React Native对接Django登录功能报错及提交问题解决
问题解决方案
问题1:无http前缀的请求错误与未处理Promise拒绝
原因
- 请求地址未加
http前缀时,React Native的fetch会将其视为相对路径,导致请求无法正确发送到后端接口,触发错误。 - AuthContext中的错误捕获逻辑错误:
.catch(({ e }) => { ... })是错误的解构方式,实际catch接收的是错误对象本身,导致错误未被正确捕获,引发未处理的Promise拒绝。 - 直接将Error对象赋值给
error状态并渲染到React组件中,React无法渲染对象类型,因此出现Objects are not valid as a React child错误。
修复步骤
- 保留请求地址的http前缀:React Native中调用外部接口必须使用完整的协议+域名/IP+端口的地址,不能省略
http/https。 - 修复错误捕获逻辑:修改AuthContext中的
onLogin方法,调整加载状态时机和错误捕获方式:const onLogin = (email, password) => { console.log("HELLO2"); setIsLoading(true); // 请求开始时立即设置加载状态 loginRequest(email, password) .then((loginUser) => { setUser(loginUser); setError(null); // 登录成功清空错误状态 }) .catch((e) => { // 直接接收错误对象,避免错误解构 setError(e.message || '登录失败'); // 提取错误信息,避免渲染对象 }) .finally(() => { // 无论成功失败,最终关闭加载状态 setIsLoading(false); }); }; - 优化loginRequest的错误处理:后端返回的是字段级错误数组,将其转换为可读字符串,确保抛出的Error有有效message:
export const loginRequest = async (email, password) => { console.log("login", email, password); // 打印参数,确认传递值是否正确 const response = await fetch("http://172.25.80.1:19000/api/user/token/", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: email, password: password, }), }); const data = await response.json(); console.log(data); if (!response.ok) { // 拼接所有后端返回的错误信息 const errorMessages = Object.values(data).flat().join(' '); throw new Error(errorMessages || '登录请求失败'); } return data; };
问题2:后端返回邮箱无效、密码必填的验证错误
原因
- 字段名不匹配:Django REST Framework默认的Token认证接口(如
api-token-auth/)接受username和password字段,而前端传递的是email字段,后端无法识别导致验证失败。 - 输入参数为空:点击登录时,email或password的state值可能为空,后端接收到空值触发验证错误。
修复步骤
- 对齐前后端字段名:
- 如果使用DRF默认Token认证,前端将email的值放在
username字段传递:// 修改loginRequest中的body部分 body: JSON.stringify({ username: email, // 把邮箱作为用户名传递 password: password, }), - 如果后端是自定义Token接口,确保序列化器中配置了
email和password字段。
- 如果使用DRF默认Token认证,前端将email的值放在
- 验证前端输入参数:在
onLogin中打印参数,确认点击登录时email和password不为空:const onLogin = (email, password) => { console.log('登录参数:', email, password); // 检查参数是否有效 // ... 后续逻辑 }; - 后端自定义邮箱登录序列化器(可选):若要让后端直接支持邮箱登录,可自定义序列化器替换默认的AuthTokenSerializer:
然后在urls.py中配置使用该序列化器的视图:from rest_framework import serializers from django.contrib.auth import authenticate from django.utils.translation import gettext_lazy as _ class EmailTokenSerializer(serializers.Serializer): email = serializers.EmailField() password = serializers.CharField(style={'input_type': 'password'}) def validate(self, attrs): email = attrs.get('email') password = attrs.get('password') if email and password: user = authenticate(request=self.context.get('request'), username=email, password=password) if not user: raise serializers.ValidationError(_('无效的邮箱或密码')) else: raise serializers.ValidationError(_('必须填写邮箱和密码')) attrs['user'] = user return attrsfrom rest_framework.authtoken.views import ObtainAuthToken from .serializers import EmailTokenSerializer from django.urls import path urlpatterns = [ path('api/user/token/', ObtainAuthToken.as_view(serializer_class=EmailTokenSerializer), name='token'), ]
内容的提问来源于stack exchange,提问作者mightycode Newton
相关产品推荐
相关产品推荐

