如何在Dart的http请求中添加查询参数?

120

如何在Dart http get请求中正确添加查询参数?当我尝试将“?param1=one&param2=two”附加到我的URL时,我的请求无法正确响应,但在Postman中却可以正常工作。以下是我的代码要点:

    final String url = "https://www.myurl.com/api/v1/test/";
    String workingStringInPostman = "https://www.myurl.com/api/v1/test/123/?param1=one&param2=two";

    Map<String, String> qParams = {
     'param1': 'one',
     'param2': 'two',
    };


   var res = await http
      .get(Uri.encodeFull("$url${widget.pk}/"),
      headers: {HttpHeaders.authorizationHeader: "Token $token", 
        HttpHeaders.contentTypeHeader: "application/json"},
);

${widget.pk}是传递的整数值(请参见workingStringInPostman变量中的值123)。

qParams存在是为了方便,以防需要Uri参数。

欢迎提供代码示例。

13个回答

207

你需要构造一个Uri并将其用于请求。类似以下内容:

final queryParameters = {
  'param1': 'one',
  'param2': 'two',
};
final uri =
    Uri.https('www.myurl.com', '/api/v1/test', queryParameters);
final response = await http.get(uri, headers: {
  HttpHeaders.authorizationHeader: 'Token $token',
  HttpHeaders.contentTypeHeader: 'application/json',
});

请查看 https://api.dartlang.org/stable/2.0.0/dart-core/Uri/Uri.https.html


2
主机和路径的分离是答案。 - Peter Birdsall
23
这里的widget.pk表示小部件对象的主键。 - IamVariable
3
由于某种原因,应用程序在Uri.https之后停止运行,就像发生异常一样,但没有错误提示,它只是停止了。 - Pablo
2
如果URL是本地主机且带有端口,例如localhost:5001,则会出现错误。 - Tuan van Duong
1
无法使用本地地址定义API路径。 - s.j
创建一个针对localhost地址的URI。Uri.http('localhost:5001', '/api/v1/whatever', {'param1': 'one'})。如果您在使用https和localhost时遇到问题,可能是证书问题。 - Nate Bosch

45

这更简单了。

final uri = Uri.parse('$baseUrl/v1/endpoint').replace(queryParameters: {
      'page': page,
      'itemsPerPage': itemsPerPage,
    });
final response = await client.get(uri);

这对于HTTP包来说非常容易,但对于Dio包来说不太容易。 - ᴅ ᴇ ʙ ᴊ ᴇᴇ ᴛ
无法正常工作,它只添加了前两个查询参数。 - Kristi Jorgji

38

如果您不希望覆盖基本终端点的方案,请使用以下技术将映射转换为查询字符串并将其附加到基本终端点 URL。

var endpointUrl = 'https://www.myurl.com/api/v1/user';
Map<String, String> queryParams = {
  'param1': '1',
  'param2': '2'
};

var headers = {
  HttpHeaders.authorizationHeader: 'Token $token',
  HttpHeaders.contentTypeHeader: 'application/json',
}

String queryString = Uri.parse(queryParameters: queryParams).query;

var requestUrl = endpointUrl + '?' + queryString; // result - https://www.myurl.com/api/v1/user?param1=1&param2=2
var response = await http.get(requestUrl, headers: headers);

4
很遗憾,这不再起作用了。在http.get(requestUrl...)处会抛出一个错误。参数类型“String”无法赋值给参数类型“Uri”。 - Ojonugwa Jude Ochalifu
3
只需将该字符串放在 Uri.parse() 中即可。 - Jaidyn Belbin
1
我没有看到 Uri.parse 的任何参数 queryParameters - trinalbadger587
Uri.parse() 中不存在参数 queryParameters. - Eric Valero
1
使用Uri(queryParameters: queryParams)代替Uri.parse() - undefined

8

我有同样的问题。如果我的URL是带有端口号的本地主机,例如https://localhost:5001,那么接受的答案将无法工作。经过花费一天的时间寻找解决方案,我得到了Dio库。以下是我使用Dio的解决方案:

var _dio = new Dio();
var options = new Options;
options.headers['Authorization'] = 'bearer $token';
options.contentType = 'application/json';
String url = "https://www.myurl.com";
Map<String, String> qParams = {
  'param1': 'one',
  'param2': 'two',
};

var res = await _dio.get(url, options: options, queryParameters: qParams);

希望这能帮到您。

仍然出现以下错误 - 未处理的异常:NoSuchMethodError:在null上调用了方法'[]'。 E / flutter(12741):接收器:null E / flutter(12741):尝试调用:[](“BankName”) - s.j
你能提供任何解决方案吗? - s.j
为了获得一个 List<String> 的响应,我不得不执行 _dio.get<List<dynamic>>(...).data.cast<String>();。如果有更好的方法,请随时告诉我。 - Stack Underflow
应该是 options.headers = {'Authorization': 'bearer $token'}; - Stack Underflow

6

使用Uri来传递查询参数,如下所示。

final String url = "https://www.myurl.com/api/v1/test/${widget.pk}/";

Map<String, String> qParams = {
 'param1': 'one',
 'param2': 'two',
};
Map<String, String> header = {
HttpHeaders.authorizationHeader: "Token $token", 
    HttpHeaders.contentTypeHeader: "application/json"
};

Uri uri = Uri.parse(url);
final finalUri = uri.replace(queryParameters: qParams); //USE THIS

final response = await http.get(
  finalUri,
  headers: header,
);

6
使用Uri构造函数来构建查询,它具有queryParameter属性。
var uri = Uri(
  scheme: 'https',
  host: 'example.com',
  path: '/foo/bar',
  fragment: 'baz',
  queryParameters: _yourQueryParameters,
);

var response = await http.get(uri);
if (response.statusCode == 200) {
  var json = jsonDecode(response.body);
  // Do whatever you want to do with json. 
}

4
接受的答案对我没有用,但在URL末尾添加一个'&'(不带引号)可以解决我的问题。在这种情况下,请更改以下行:
String workingStringInPostman = "https://www.myurl.com/api/v1/test/123/?param1=one&param2=two";

转化为:(注意结尾处的“&”)
String workingStringInPostman = "https://www.myurl.com/api/v1/test/123/?param1=one&param2=two&";

最简单且最佳的解决方案 - SardorbekR

2

有一个Dart包提供了一些帮助类来处理HTTP请求。

BasicUtils: https://github.com/Ephenodrom/Dart-Basic-Utils

安装方法:

dependencies:
  basic_utils: ^1.4.0

使用方法

您可以为每个请求添加头部和查询参数的映射地图。参考以下示例:

最初的回答:

您可以在每个请求中添加头部和查询参数的映射。下面是一个示例:

// Define some headers and query parameters
Map<String, String> headers = {
  "Accept": "application/json"
};
Map<String, String> queryParameters = {
  "foo": "bar"
};

// Body
String body = "{ 'some':'json'}";

// Send request
Map<String, dynamic> responseData = await HttpUtils.postForJson("api.com/dosomething", body,
      headers: headers, queryParameters: queryParameters);

最初的回答:

附加信息:

这些都是来自HttpUtils类的方法。

Future<Map<Response> getForFullResponse(String url,{Map<String, dynamic> queryParameters,Map<String, String> headers});
Future<Map<String, dynamic>> getForJson(String url,{Map<String, dynamic> queryParameters,Map<String, String> headers});
Future<String> getForString(String url,{Map<String, dynamic> queryParameters,Map<String, String> headers});
Future<Map<Response> postForFullResponse(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<Map<String, dynamic>> postForJson(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<String> postForString(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<Response> putForFullResponse(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<Map<String, dynamic>> putForJson(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<String> putForString(String url, String body,{Map<String, String> queryParameters,Map<String, String> headers});
Future<Response deleteForFullResponse(String url,{Map<String, String> queryParameters,Map<String, String> headers});
Future<Map<String, dynamic>> deleteForJson(String url,{Map<String, String> queryParameters,Map<String, String> headers});
Future<String> deleteForString(String url,{Map<String, String> queryParameters,Map<String, String> headers});
Map<String, dynamic> getQueryParameterFromUrl(String url);
String addQueryParameterToUrl(String url, Map<String, dynamic> queryParameters);

1
下面这个从Flutter代码复制的函数可以用来创建仅包含查询字符串部分的内容:
String queryString(Map<String, dynamic> queryParameters) {
  var result = StringBuffer();
  var separator = "";

  void writeParameter(String key, String? value) {
    result.write(separator);
    separator = "&";
    result.write(Uri.encodeQueryComponent(key));
    if (value != null && value.isNotEmpty) {
      result.write("=");
      result.write(Uri.encodeQueryComponent(value));
    }
  }

  queryParameters.forEach((key, value) {
    if (value == null || value is String) {
      writeParameter(key, value);
    } else {
      Iterable values = value;
      for (String value in values) {
        writeParameter(key, value);
      }
    }
  });
  return result.toString();
}

使用方法:

var q = queryString({"a":"b&", "c":["1","xyz"]});
// a=b%26&c=1&c=xyz

0
我写了一个小的实用函数,用于解析Uri创建中的authority / unencodedPath参数。
Uri createUri(String url, [Map<String, String> queryParameters]) {
  var isHttp = false;
  if (url.startsWith('https://') || (isHttp = url.startsWith('http://'))) {
    var authority = url.substring((isHttp ? 'http://' : 'https://').length);
    String path;
    final index = authority.indexOf('/');

    if (-1 == index) {
      path = '';
    } else {
      path = authority.substring(index);
      authority = authority.substring(0, authority.length - path.length);
    }

    if (isHttp) {
      return Uri.http(authority, path, queryParameters);
    } else {
      return Uri.https(authority, path, queryParameters);
    }
  } else if (url.startsWith('localhost')) {
    return createUri('http://' + url, queryParameters);
  }

  throw Exception('Unsupported scheme');
}

以下是使用它的示例代码:

final String url = 'https://www.myurl.com/api/v1/test/${widget.pk}';
Map<String, String> qParams = {
  'param1': 'one',
  'param2': 'two',
};

var res = await http.get(
  createUri(url, qParams),
  headers: {
    HttpHeaders.authorizationHeader: "Token $token",
    HttpHeaders.contentTypeHeader: "application/json"
  },
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接