Flutter HTTP 请求使用 xml 正文发送

Posted

技术标签:

【中文标题】Flutter HTTP 请求使用 xml 正文发送【英文标题】:Flutter HTTP request send using xml body 【发布时间】:2020-02-12 09:52:49 【问题描述】:

我正在尝试在 Flutter/Dart 中处理 HTTP 请求(在本例中使用 SEARCH 方法过滤 WebDAV 服务器 (Nextcloud) 上的某些文件)需要在请求的正文中发送 XML 数据。

[x] 可以通过 --data 参数在终端上使用 cURL 执行命令:

curl -u user:pass -X SEARCH 'https://host123.com.br/remote.php/dav' -H "content-Type: text/xml" --data '<?xml version="1.0" encoding="UTF-8"?><d:searchrequest xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns"><d:basicsearch><d:select><d:prop><d:displayname/></d:prop></d:select><d:from><d:scope><d:href>/files/wprech</d:href><d:depth>infinity</d:depth></d:scope></d:from><d:where><d:and><d:or><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>image/png</d:literal></d:eq><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>image/jpg</d:literal></d:eq><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>video/mp4</d:literal></d:eq></d:or></d:and></d:where><d:orderby/></d:basicsearch></d:searchrequest>'

[x] 也可以通过 Postman 应用工作:

[ ] 无法使用 Flutter/Dart 对 xml 正文执行此请求。 我们使用 DIO pkg 这个项目的所有其他 HTTP 请求,它工作正常,但问题是。用它发送 xml 正文。最接近的代码如下:

void _list() async 
final prefs = await SharedPreferences.getInstance();

var us = prefs.getString('id') ?? '';
var sn = prefs.getString('password') ?? '';

String basicAuth = 'Basic ' + base64Encode(utf8.encode('$us:$sn'));

try 
  Dio dio = new Dio();
  dio.options.method = 'SEARCH';
  dio.options.responseType = ResponseType.plain;
  dio.options.headers = 
    HttpHeaders.authorizationHeader: basicAuth,
    'content-Type': 'text/xml'
  ;
  String data =
      '<?xml version="1.0" encoding="UTF-8"?><d:searchrequest xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns"><d:basicsearch><d:select><d:prop><d:displayname/></d:prop></d:select><d:from><d:scope><d:href>/files/wprech</d:href><d:depth>infinity</d:depth></d:scope></d:from><d:where><d:and><d:or><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>image/png</d:literal></d:eq><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>image/jpg</d:literal></d:eq><d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>video/mp4</d:literal></d:eq></d:or></d:and></d:where><d:orderby/></d:basicsearch></d:searchrequest>';

  Response response = await dio.request(
      "https://host123.com.br/remote.php/dav",
      data: data);

  print(response);
 catch (e) 
  print(e);

服务器响应在 400、404、500 和 501 之间变化,具体取决于其发送方式:

I/flutter ( 6767): DioError [DioErrorType.RESPONSE]: Http status error [400]

有什么帮助吗? :)

【问题讨论】:

你试过package:http吗?用正确的方法创建一个BaseRequest,然后send()它。 @RichardHeap 找不到任何使用包的示例:http 并发送 xml 正文和自定义方法(如“搜索”)。有吗? 不,但是很容易拼凑起来。 (正文是 XML 并没有什么特别之处 - 它只是一个字符串。)作为答案发布。 【参考方案1】:

用更简单的package:http 版本进行实验。

import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;

main() async 
  var username = 'foo';
  var password = 'B@r!';
  var credential = base64.encode(utf8.encode('$username:$password'));
  var client = http.IOClient();

  var request = http.Request(
    'SEARCH',
    Uri.parse('https://host123.com.br/remote.php/dav'),
  );
  request.headers.addAll(
    HttpHeaders.authorizationHeader: 'Basic $credential',
    'content-type': 'text/xml' // or text/xml;charset=utf-8
  );

  var xml = '<?xml version="1.0" encoding="UTF-8"?>...';
  // either
  request.body = xml;
  // which will encode the string to bytes, and modify the content-type header, adding the encoding
  // or
  // request.bodyBytes = utf8.encode(xml);
  // which gives you complete control over the character encoding

  var streamedResponse = await client.send(request);
  print(streamedResponse.statusCode);

  var responseBody =
      await streamedResponse.stream.transform(utf8.decoder).join();
  print(responseBody);
  client.close();

【讨论】:

我使用了你的 sn-p,现在它返回状态码 207,与邮递员返回的代码相同,这是一个进步。如何按预期打开响应数据?尝试在 print(streamedResponse.xxxx) 上自动完成,但没有返回响应正文或数据。 StreamedResponse 使用名为 stream 的 getter 自动完成,这是一个 ByteStream。您可能需要一个字符串,而不是字节流,因此您必须将字节转换为具有字符编码的字符,然后将字符串的任何部分组合成一个。答案已更新。 终于成功了!不能感谢你。如果你在这附近,我会给你买啤酒?。再次感谢。

以上是关于Flutter HTTP 请求使用 xml 正文发送的主要内容,如果未能解决你的问题,请参考以下文章