【问题标题】:Dart: convert map into query stringDart:将地图转换为查询字符串
【发布时间】:2013-12-27 17:17:16
【问题描述】:

我有一种情况需要将Map 转换为查询字符串(在第一个? 之后)。例如,如果我有以下地图:

Map json = {
    "email":  eml,
    "password": passwd
};

还有一个基本 URL:

String baseURL = "http://localhost:8080/myapp";

然后我需要将 json Map 转换为基本 URL 的查询字符串的东西:

String fullURL = parameterizeURL(baseURL, json);

// Prints: http://localhost:8080/myapp?email=blah&password=meh
// (if "blah" was entered as the email, and "meh" was entered as the password)
print(fullURL);

我在 Git 上找到了this query String-to-map library,但我需要这个的!如果也能在其中获得 URL 编码,那就太好了。

我很高兴自己制作一些东西,但对 Dart 来说如此陌生,我想知道 pub/Github/etherspehere 上是否有任何东西已经这样做了。

【问题讨论】:

    标签: url map type-conversion query-string dart


    【解决方案1】:

    你看过 dart:core 中的 Uri 类吗?您可以从 Url 组件构造一个 Uri 类:

    new Uri({String scheme, String userInfo: "", String host: "", port: 0, String path, 
      Iterable<String> pathSegments, String query, 
      Map<String, String> queryParameters, fragment: ""}) #
    

    请注意,您将查询字符串作为映射传递,如果您使用的是不采用此类的 HTTP 客户端,则可以 .toString 获取 URL。

    我在我的代码中使用它而不是字符串 Url's

    作为使用上述数据的示例:

    void main() {
    
          String eml = "me@here.com";
          String passwd = "password";
    
          Map json = {
                      "email":  eml,
                      "password": passwd
          };  
    
    
          Uri outgoingUri = new Uri(scheme: 'http',
              host: 'localhost',
              port: 8080,
              path: 'myapp',
              queryParameters:json);
    
          print(outgoingUri);
    
        }
    

    这打印:

    http://localhost:8080/myapp?email=me%40here.com&password=password
    

    请注意,一旦构造了 Uri,它就是不可变的,即您不能再次更改查询参数。 pub 中还有this 包,虽然我还没有使用过,但它可能会提供更多便利。

    【讨论】:

    • 谢谢@user2685314 (+1) - 你能给我看一个实际的代码示例吗,也许使用我上面的电子邮件/密码示例?再次感谢!!!
    • 为什么这不是公认的答案?也可以使用Uri构造函数,只带queryParameters参数,将Map转换为查询字符串,非常方便。
    • 它不会转换非字符串值,如 int 或 bool
    【解决方案2】:

    TL;DR

    String queryString = Uri(queryParameters: {'x': '1', 'y': '2'}).query;
    
    print(queryString); // x=1&y=2
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关此代码为何和/或如何回答问题的额外上下文可提高其长期价值。
    • 值得一提的是queryParameters只能是Map&lt;String, String&gt;Map&lt;String, Iterable&lt;String&gt;&gt;。不幸的是,它还不够智能,无法自动为Map&lt;String, dynamic&gt; 类型的.toString() 值。 api.dart.dev/stable/2.0.0/dart-core/Uri/Uri.html以下逻辑转换我的动态地图以供我使用:Uri(queryParameters: json.map((key, value) =&gt; MapEntry(key, value == null ? null : value.toString()))).query
    【解决方案3】:
    final yourMap = {'x': '1', 'y': '2'};
    final queryString = yourMap.toMap().entries.map((e) => '${e.key}=${e.value}').join('&');
    print(queryString); // x=1&y=2
    

    【讨论】:

      【解决方案4】:

      我编写了一个递归函数来将任何Map&lt;String, dynamic&gt; 转换为查询String

      String getQueryString(Map params, {String prefix: '&', bool inRecursion: false}) {
      
          String query = '';
      
          params.forEach((key, value) {
      
              if (inRecursion) {
                  key = '[$key]';
              }
      
              if (value is String || value is int || value is double || value is bool) {
                  query += '$prefix$key=$value';
              } else if (value is List || value is Map) {
                  if (value is List) value = value.asMap();
                  value.forEach((k, v) {
                      query += getQueryString({k: v}, prefix: '$prefix$key', inRecursion: true);
                  });
              }
         });
      
         return query;
      }
      

      示例:

      Map<String, dynamic> params = {'aa': 1.1, 'bb': [2, [3, ['5', {'66': 777}]]]};
      String query = getQueryString(params);
      print(query);
      

      此代码将打印:

      &aa=1.1&bb[0]=2&bb[1][0]=3&bb[1][1][0]=5&bb[1][1][1][66]=777
      

      【讨论】:

      • 喜欢吗?我使用了您将作为查询参数发送的最合理的类型。
      • print(Uri(queryParameters: {'name': 'John Deo', 'age': '25'}).query);
      • 这是最骇人听闻的
      【解决方案5】:

      如果你使用 Dio 库,你可能会使用 Transformer.urlEncodeMap。它接受 Map

      String Transformer.urlEncodeMap(Map<String, dynamic>)
      

      您可以在此处的官方文档中找到它:https://pub.dev/documentation/dio/latest/dio/Transformer/urlEncodeMap.html

      【讨论】:

        【解决方案6】:

        我遇到了同样的问题并为我编写了这个函数。这是以防有人需要它:

        String makeQuery(Map<String, dynamic>? data) {
          var result = [];
        
          if (data != null) {
            data.forEach((key, value) {
              if (value != null && (value is! String || value.trim().isNotEmpty)) {
                result.add('$key=${value.toString()}');
              }
            });
          }
        
          return result.join('&');
        }
        

        【讨论】:

          【解决方案7】:

          你能描述一下你的用法吗?首先,在 GET 请求中保留密码等数据不是好的做法。这最好是一个 POST 请求。也就是说,如果您确实想将其用作 POST 请求以将地图发送到服务器,请查看:HttpRequest.postFormData 它会自动将您提供的地图作为 POST 数据添加到服务器。要记住的一个警告是数据必须是 Map(或键和值必须是字符串)。示例用法:

          import 'dart:html';
          // ...
          
          // Somewhere in your login related method
          HttpRequest.postFormData('login.php', data).then((HttpRequest req) {
            if(req.status != 200) {
              print(req.statusText);
            }
          });
          

          有一个可用于服务器端 Dart 的包,它允许您轻松编写手动处理各种 HTTP 请求,恰当地命名为 http。但是,这不适用于客户端脚本。我不知道有任何现有的软件包可以提供您正在寻找的功能。

          关于这一点,如果您决定推出自己的产品,也许可以向您在问题中提到的 QueryString 项目提供一个拉取请求,以便其他人可以在一个简单的包中使用该功能。

          【讨论】:

          • 感谢@Matt B (+1) - 我猜电子邮件/密码是一个糟糕的用例。假设我想构建一个 URL 以在 GET 端点访问第 3 方 RESTful API,例如:(GET) http://api.somevendor.example.com/widgets?fragile=true&amp;size=4&amp;color=red。在这种情况下,我想要将 Map params = { "fragile": true, "size": 4, "color": "red" }; 转换为 URL 的东西。再一次,我很高兴自己做这件事,但在我发挥精神能量之前,我想知道 Dart 是否有任何东西已经这样做了——没有意义重新发明轮子。
          • 更新了我对服务器端的响应。但最终不,我不知道现有的包在客户端提供该功能。
          • 这不是所提问题的答案,尽管它是一个合法的答案。
          【解决方案8】:

          我认为从Map 生成查询字符串的最简单方法是使用Uri.replace。这与使用Uri constructor 基本相同,但它避免了需要手动复制 URL 的所有其他部分:

          String baseURL = "http://localhost:8080/myapp";
          
          Map json = {
            "email":  eml,
            "password": passwd
          };
          
          String fullURL = Uri.parse(baseURL).replace(queryParameters: json).toString();
          

          我意识到我在回答一个老问题,但我不得不另外指出,您可能不应该通过查询字符串发送密码。

          【讨论】:

            猜你喜欢
            • 2011-02-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多