You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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请求头截图:
Postman请求头

解决方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 09:54:51