Flutter调用SAP ABAP API时x-csrf-token导致403错误的解决办法
Flutter调用SAP ABAP API时x-csrf-token无效导致403的解决方案
问题概述
在Flutter中通过HTTP POST请求调用SAP ABAP开发的API,采用x-csrf-token机制验证身份,已成功获取token并传入请求头,但仍返回403错误。相关代码如下:
Future<void> postData() async { final Map<String, dynamic> data = { "Bukrs": "ABC", "Hbkid": "12345", "Kunnr": "67890", "Name1": "Örnek İsim", "Waers": "USD", "Dlimt": "10000", "Rlimt": "5000", "Klimt": "7500", "Blimt": "3000" }; print( jsonEncode(data)); String csrfToken =''; String cookie =''; String basicAuth = 'Basic ' + base64Encode(utf8.encode('$username:$password')); final String apiUrl2 = "url2)?\$format=json"; try { final response = await http.get( Uri.parse(apiUrl2), headers: <String, String>{ 'Authorization': basicAuth, 'x-csrf-token': 'fetch', }, ); if (response.statusCode == 200) { print(json.decode(response.body)); csrfToken = response.headers['x-csrf-token']!; cookie = response.headers['set-cookie']!; print("x-csrf-token: $csrfToken"); print("\n *----------------------cookie: $cookie"); } else { print("HATAAAA: ${response.statusCode}"); } } catch (e) { print("Hata oluştu: $e"); } String basicAuth2 = 'Basic ' + base64Encode(utf8.encode('$username:$password')); final String apiUrl = "url"; print(csrfToken); try { final response = await http.post( Uri.parse(apiUrl), headers:{ 'Authorization': basicAuth2, 'x-csrf-token': csrfToken, 'Content-type': 'application/json', 'Cookie': cookie, }, body: jsonEncode(data), ); print('Gönderilen Headerlar: ${response.request!.headers}'); if (response.statusCode == 200) { print("Veri başarıyla gönderildi"); } else { print("Veri gönderme başarısız: ${response.statusCode}"); } } catch (e) { print("Hata oluştu: $e"); } }
Postman请求头截图:
解决方案
1. 正确解析Session Cookie
SAP的x-csrf-token与会话Cookie强绑定,直接把set-cookie的完整值传入会包含多余属性(如path、HttpOnly等),导致Cookie无效。需要提取仅包含键值对的会话Cookie:
添加Cookie解析方法:
String parseCookie(String setCookie) { // 拆分多个Cookie,只保留key=value部分 return setCookie.split(',').map((cookieSegment) { return cookieSegment.split(';').first.trim(); }).join('; '); }
修改获取Cookie的逻辑:
if (response.statusCode == 200) { print(json.decode(response.body)); csrfToken = response.headers['x-csrf-token']!; final rawSetCookie = response.headers['set-cookie']!; cookie = parseCookie(rawSetCookie); // 使用解析后的Cookie print("x-csrf-token: $csrfToken"); print("\n *----------------------cookie: $cookie"); }
2. 统一请求头格式
- 将
Content-type修正为标准的Content-Type(HTTP头建议使用标准大小写) - 复用同一个Basic Auth凭证,无需重复生成
3. 确保Token与请求同域
获取x-csrf-token的URL(apiUrl2)和POST请求的URL(apiUrl)必须属于同一个SAP系统域,否则Token会因跨会话失效。
4. 排查SAP端配置
- 确认当前用户拥有该POST API的调用权限
- 检查SAP ICF节点的CORS配置,允许Flutter应用的请求来源
- 查看SAP返回的响应体,获取具体错误信息(在POST请求失败时打印
response.body)
修改后的完整代码
Future<void> postData() async { final Map<String, dynamic> data = { "Bukrs": "ABC", "Hbkid": "12345", "Kunnr": "67890", "Name1": "Örnek İsim", "Waers": "USD", "Dlimt": "10000", "Rlimt": "5000", "Klimt": "7500", "Blimt": "3000" }; print(jsonEncode(data)); String csrfToken = ''; String cookie = ''; final String basicAuth = 'Basic ' + base64Encode(utf8.encode('$username:$password')); final String apiUrl2 = "url2)?\$format=json"; // 解析Set-Cookie,提取有效会话Cookie String parseCookie(String setCookie) { return setCookie.split(',').map((cookieSegment) { return cookieSegment.split(';').first.trim(); }).join('; '); } try { final response = await http.get( Uri.parse(apiUrl2), headers: <String, String>{ 'Authorization': basicAuth, 'x-csrf-token': 'fetch', }, ); if (response.statusCode == 200) { print(json.decode(response.body)); csrfToken = response.headers['x-csrf-token']!; final rawSetCookie = response.headers['set-cookie']!; cookie = parseCookie(rawSetCookie); print("x-csrf-token: $csrfToken"); print("\n *----------------------cookie: $cookie"); } else { print("HATAAAA: ${response.statusCode}"); print("Token获取失败详情: ${response.body}"); } } catch (e) { print("Token获取时出错: $e"); } final String apiUrl = "url"; print(csrfToken); try { final response = await http.post( Uri.parse(apiUrl), headers: { 'Authorization': basicAuth, 'x-csrf-token': csrfToken, 'Content-Type': 'application/json', // 修正为标准头 'Cookie': cookie, }, body: jsonEncode(data), ); print('发送的请求头: ${response.request!.headers}'); if (response.statusCode == 200) { print("数据发送成功"); } else { print("数据发送失败: ${response.statusCode}"); print("错误详情: ${response.body}"); // 打印SAP返回的具体错误 } } catch (e) { print("数据发送时出错: $e"); } }
内容的提问来源于stack exchange,提问作者Mert
相关产品推荐
相关产品推荐

