React Native登录接口数据未发送,返回参数验证错误
移动端登录请求数据未发送,Web/Postman正常,React Native返回验证错误
问题现象
- 移动端登录时,接口返回错误:
{"message":"email must be an email, password must be a string"} - Web端和Postman测试登录接口完全正常
- 错误日志显示Axios发送的请求体为空对象:
"data": "{}"
Axios集成代码
export const SignInBody = () => { const [passwordVisible, setPasswordVisible] = useState(true); const navigation = useNavigation(); const [login, setLogin] = useState(''); const [password, setPassword] = useState(''); const handleLogin = () => { axios .post(`${PROTOCOL}${REACT_APP_BACK_URL}/login`, { email: login, password: password, }) .then(function (response) { AsyncStorage.setItem('userId', response.data.data.id)?.toString(); navigation.navigate('Root', { screen: 'one' }); }) .catch(function (error) { console.log(error.response); errorAlert({ title: 'Atenção', msg: 'Email ou senha incorretos', btn: 'Ok', }); }); };
完整错误信息
Object { "config": Object { "adapter": [Function xhrAdapter], "data": "{}", "env": Object { "FormData": null, }, "headers": Object { "Accept": "application/json, text/plain, */*", "Content-Type": "application/json", }, "maxBodyLength": -1, "maxContentLength": -1, "method": "post", "timeout": 0, "transformRequest": Array [ [Function transformRequest], ], "transformResponse": Array [ [Function transformResponse], ], "transitional": Object { "clarifyTimeoutError": false, "forcedJSONParsing": true, "silentJSONParsing": true, }, "url": "https://mybackurl", "validateStatus": [Function validateStatus], "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", }, "data": Object { "message": "email must be an email, password must be a string", }, "headers": Object { "access-control-allow-credentials": "true", "access-control-allow-origin": "*", "connection": "keep-alive", "content-length": "63", "content-security-policy": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", "content-type": "application/json; charset=utf-8", "date": "Fri, 15 Jul 2022 03:59:44 GMT", "etag": "W/\"3f-ALOE7r8MX9pcEta7jauOf258lOM\"", "expect-ct": "max-age=0", "referrer-policy": "no-referrer", "server": "Cowboy", "strict-transport-security": "max-age=15552000; includeSubDomains", "vary": "Accept-Encoding", "via": "1.1 vegur", "x-content-type-options": "nosniff", "x-dns-prefetch-control": "off", "x-download-options": "noopen", "x-frame-options": "SAMEORIGIN", "x-permitted-cross-domain-policies": "none", "x-xss-protection": "0", }, "request": XMLHttpRequest { "DONE": 4, "HEADERS_RECEIVED": 2, "LOADING": 3, "OPENED": 1, "UNSENT": 0, "_aborted": false, "_cachedResponse": undefined, "_hasError": false, "_headers": Object { "accept": "application/json, text/plain, */*", "content-type": "application/json", }, "_incrementalEvents": false, "_lowerCaseResponseHeaders": Object { "access-control-allow-credentials": "true", "access-control-allow-origin": "*", "connection": "keep-alive", "content-length": "63", "content-security-policy": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", "content-type": "application/json; charset=utf-8", "date": "Fri, 15 Jul 2022 03:59:44 GMT", "etag": "W/\"3f-ALOE7r8MX9pcEta7jauOf258lOM\"", "expect-ct": "max-age=0", "referrer-policy": "no-referrer", "server": "Cowboy", "strict-transport-security": "max-age=15552000; includeSubDomains", "vary": "Accept-Encoding", "via": "1.1 vegur", "x-content-type-options": "nosniff", "x-dns-prefetch-control": "off", "x-download-options": "noopen", "x-frame-options": "SAMEORIGIN", "x-permitted-cross-domain-policies": "none", "x-xss-protection": "0", }, "_method": "POST", "_perfKey": "network_XMLHttpRequest_https://mybackurl", "_performanceLogger": PerformanceLogger { "_closed": false, "_extras": Object {}, "_pointExtras": Object {}, "_points": Object { "initializeCore_end": 1657857539044, "initializeCore_start": 1657857538868, }, "_timespans": Object { "network_XMLHttpRequest_http://192.168.15.7:19000/logs": Object { "endExtras": undefined, "endTime": 1657857540601, "startExtras": undefined, "startTime": 1657857540513, "totalTime": 88, }, "network_XMLHttpRequest_http://192.168.15.7:19000/symbolicate": Object { "endExtras": undefined, "endTime": 1657857540548, "startExtras": undefined, "startTime": 1657857540120, "totalTime": 428, }, "network_XMLHttpRequest_https://mybackurl": Object { "endExtras": undefined, "endTime": 1657857583334, "startExtras": undefined, "startTime": 1657857558247, "totalTime": 25087, }, }, }, "_requestId": null, "_response": "{\"message\":\"email must be an email, password must be a string\"}", "_responseType": "", "_sent": true, "_subscriptions": Array [], "_timedOut": false, "_trackingName": "unknown", "_url": "MYBACKURL", "readyState": 4, "responseHeaders": Object { "Access-Control-Allow-Credentials": "true", "Access-Control-Allow-Origin": "*", "Connection": "keep-alive", "Content-Length": "63", "Content-Security-Policy": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", "Content-Type": "application/json; charset=utf-8", "Date": "Fri, 15 Jul 2022 03:59:44 GMT", "Etag": "W/\"3f-ALOE7r8MX9pcEta7jauOf258lOM\"", "Expect-Ct": "max-age=0", "Referrer-Policy": "no-referrer", "Server": "Cowboy", "Strict-Transport-Security": "max-age=15552000; includeSubDomains", "Vary": "Accept-Encoding", "Via": "1.1 vegur", "X-Content-Type-Options": "nosniff", "X-Dns-Prefetch-Control": "off", "X-Download-Options": "noopen", "X-Frame-Options": "SAMEORIGIN", "X-Permitted-Cross-Domain-Policies": "none", "X-Xss-Protection": "0", }, "responseURL": "MYBACKURL", "status": 400, "timeout": 0, "upload": XMLHttpRequestEventTarget {}, "withCredentials": true, }, "status": 400, "statusText": undefined, }
排查与解决方案
从"data": "{}"可以确定,请求体未正确携带email和password参数,导致后端验证失败,可按以下步骤解决:
1. 检查输入框状态绑定
确保输入框的value和onChangeText正确绑定到对应状态:
// 示例绑定代码 <TextInput value={login} onChangeText={setLogin} placeholder="邮箱" /> <TextInput value={password} onChangeText={setPassword} placeholder="密码" secureTextEntry={passwordVisible} />
若绑定错误,login和password会一直为空字符串,引发序列化异常。
2. 手动序列化请求体
部分React Native环境中Axios默认序列化失效,可手动转换为JSON字符串:
axios.post(`${PROTOCOL}${REACT_APP_BACK_URL}/login`, JSON.stringify({ email: login, password: password, }), { headers: { 'Content-Type': 'application/json' } })
3. 检查Axios配置与版本
- 升级Axios到最新稳定版,规避版本兼容性问题
- 排查全局拦截器是否修改了请求体,避免出现清空数据的逻辑:
// 错误示例:拦截器清空请求体 axios.interceptors.request.use(config => { config.data = {}; return config; });
4. 调试状态值
在handleLogin中打印状态,确认参数是否正确:
const handleLogin = () => { console.log('login:', login, 'password:', password); axios.post(...) }
若打印为空,说明输入框绑定有问题;若有值但请求体为空,需排查Axios序列化逻辑。
内容的提问来源于stack exchange,提问作者Pedro Manso
相关产品推荐
相关产品推荐

