Http.post不接受flutter / dart中的内容类型application / query + json

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Http.post不接受flutter / dart中的内容类型application / query + json相关的知识,希望对你有一定的参考价值。

我正在使用flutter应用程序与天蓝色的db交谈。 cosmos db具有基于sql查询的rest api。内容类型应为application / query + json。我尝试使用邮递员连接到cosmos db,但效果很好,但是在颤抖中,我得到了例外,原因是

Bad state: Cannot set the body fields of a Request with content-type "application/query+json"

下面是示例http.post代码:

final http.Response response =
  await http.post(
      url,
      headers: {<other headers>, 'Content-Type' : 'application/query+json'},
      body: {
       "query" : "<SQL Query>",
       "parameters" : [<parameter name and value pairs>]
       },
   );

我已经在邮递员中对此进行了测试,并且可以正常工作。

如果http:dart包支持正文的内容类型application / query + json,那么我应该如何制定我的请求正文。

答案

尝试使用HttpClient:

  Future<HttpClientResponse> httpRequest(String url, Map headers, Map body, {bool isQuery = false}) async {
    HttpClient httpClient = new HttpClient();
    HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));

    headers.forEach((key, value) {
      request.headers.set(key,value);
    });
    if(isQuery) {
      request.headers.set('content-type', 'application/query+json');
      request.headers.set('x-ms-documentdb-isquery', 'True');
    }

    if(body != null) {
      request.add(utf8.encode(json.encode(body)));
    }

    HttpClientResponse response = await request.close();
    httpClient.close();

    return response;
  }

注意,您需要将标题设置为1比1。

仅执行SELECT查询的便利功能:

  Future<HttpClientResponse> doSELECTQuery(String userAgent, List<String> requiredColHeaders, String azTblName, 
      {Map<String,String> mapWHERE, String pKey, String pKey_Filter, Map<String, String> moreHeaders, String alternateCollectionUrl = null}) async {

    String _collectionUrl;
    String _host;

      Uri uri = Uri.tryParse(alternateCollectionUrl);
      if(uri != null) {
        _host = uri.host;
      }
      _collectionUrl = alternateCollectionUrl;
    } else {
      _collectionUrl = this.collectionUrl;
      _host = this.host;
    }

    String collectionPath = Uri.parse(_collectionUrl).path.substring(1);  // remove leading "/"
    Map<String, String> headers = {
      "authorization": generateAuthToken(
          "POST", "docs", collectionPath, HttpDate.format(DateTime.now()),
          masterKey, "master"),
      "x-ms-version": "2018-12-31",
      "x-ms-date": HttpDate.format(DateTime.now()),
      "user-agent": userAgent,
      "Cache-Control": "no-cache",
      "Accept": "application/json",
      "Host": _host,
      "x-ms-documentdb-partitionkey": pKey == null ? "" : "["" + pKey_Filter + ""]",
      "x-ms-documentdb-query-enablecrosspartition": pKey == null ? "True" : ""
    };

    if(moreHeaders != null) {
      headers.addAll(moreHeaders);
    }

    String strSELECT = "";
    requiredColHeaders.forEach((col) {
      strSELECT = strSELECT + "$azTblName["$col"],";
    });
    strSELECT = strSELECT.substring(0, strSELECT.length - 1); // remove trailing ","

    String strWHERE = "";
    if(mapWHERE != null) {
      mapWHERE.forEach((col, value) {
        strWHERE = strWHERE + "($azTblName["$col"] = "$value")AND";
      });
      strWHERE = strWHERE.substring(0, strWHERE.length - 3);  // remove trailing "AND"
    }

    String strQuery = "SELECT $strSELECT FROM $azTblName";
    if(strWHERE != "") {
      strQuery = strQuery + " WHERE $strWHERE";
    }

    Map<String, dynamic> body = {
      "query": strQuery,
      "parameters": []
    };
    var response = await httpRequest(_collectionUrl + "/docs", headers, body, isQuery: true);

    return response;
  }

所有内容,以及生成授权令牌的功能:

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


class azureCosmosHelper {

  String masterKey = "<your_master_key>";
  // Contains url to collection 
  String collectionUrl = "https://<your_database_account>.documents.azure.com/dbs/<your_database_id>/colls/<your_collection_id>";
  String host = "<your_database_account>.documents.azure.com";
  String pKey = "<your_partition_key>";

  Future<void> getAzureDB() {
    HttpClientResponse response = await doSELECTQuery("<userAgent>", List<String> tableColumns, "<tableName>",
              pKey: this.pKey,
              pKey_Filter: "<pKey_Filter>",
              );

    // parse response accordingly
  }


  Future<HttpClientResponse> doSELECTQuery(String userAgent, List<String> requiredColHeaders, String azTblName, 
      {Map<String,String> mapWHERE, String pKey, String pKey_Filter, Map<String, String> moreHeaders, String alternateCollectionUrl = null}) async {

    String _collectionUrl;
    String _host;

      Uri uri = Uri.tryParse(alternateCollectionUrl);
      if(uri != null) {
        _host = uri.host;
      }
      _collectionUrl = alternateCollectionUrl;
    } else {
      _collectionUrl = this.collectionUrl;
      _host = this.host;
    }

    String collectionPath = Uri.parse(_collectionUrl).path.substring(1);  // remove leading "/"
    Map<String, String> headers = {
      "authorization": generateAuthToken(
          "POST", "docs", collectionPath, HttpDate.format(DateTime.now()),
          masterKey, "master"),
      "x-ms-version": "2018-12-31",
      "x-ms-date": HttpDate.format(DateTime.now()),
      "user-agent": userAgent,
      "Cache-Control": "no-cache",
      "Accept": "application/json",
      "Host": _host,
      "x-ms-documentdb-partitionkey": pKey == null ? "" : "["" + pKey_Filter + ""]",
      "x-ms-documentdb-query-enablecrosspartition": pKey == null ? "True" : ""
    };

    if(moreHeaders != null) {
      headers.addAll(moreHeaders);
    }

    String strSELECT = "";
    requiredColHeaders.forEach((col) {
      strSELECT = strSELECT + "$azTblName["$col"],";
    });
    strSELECT = strSELECT.substring(0, strSELECT.length - 1); // remove trailing ","

    String strWHERE = "";
    if(mapWHERE != null) {
      mapWHERE.forEach((col, value) {
        strWHERE = strWHERE + "($azTblName["$col"] = "$value")AND";
      });
      strWHERE = strWHERE.substring(0, strWHERE.length - 3);  // remove trailing "AND"
    }

    String strQuery = "SELECT $strSELECT FROM $azTblName";
    if(strWHERE != "") {
      strQuery = strQuery + " WHERE $strWHERE";
    }

    Map<String, dynamic> body = {
      "query": strQuery,
      "parameters": []
    };
    var response = await httpRequest(_collectionUrl + "/docs", headers, body, isQuery: true);

    return response;
  }

  Future<HttpClientResponse> httpRequest(String url, Map headers, Map body, {bool isQuery = false}) async {
    HttpClient httpClient = new HttpClient();
    HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));

    headers.forEach((key, value) {
      request.headers.set(key,value);
    });
    if(isQuery) {
      request.headers.set('content-type', 'application/query+json');
      request.headers.set('x-ms-documentdb-isquery', 'True');
    }

    if(body != null) {
      request.add(utf8.encode(json.encode(body)));
    }

    HttpClientResponse response = await request.close();
    httpClient.close();

    return response;
  }

  //Generates authorization token
  String generateAuthToken(String verb, String resourceType, String resourceLink, String date, String key, String keyType, {String tokenVer="1.0"}) {
    String payload=verb.toLowerCase()+"
"
        +resourceType.toLowerCase()+"
"
        +resourceLink+"
"
        +date.toLowerCase()+"
"
        +""+"
";

    var key_decode = base64.decode(key);
    Hmac hmac = new Hmac(sha256, key_decode);
    var messageBytes = utf8.encode(payload);
    Digest digest = hmac.convert(messageBytes);
    String signature = base64.encode(digest.bytes);
    return Uri.encodeComponent("type="+keyType+"&ver="+tokenVer+"&sig="+signature);
  }
}

以上是关于Http.post不接受flutter / dart中的内容类型application / query + json的主要内容,如果未能解决你的问题,请参考以下文章

Dart/Flutter POST 请求和流响应

如何在 Flutter 中更改布局

为啥我在flutter中更新http包后不能在http.post方法中放一个字符串

Flutter/Dart http POST 重定向通过 GET 发送正文

Http POST 在 Postman 中有效,但在 Flutter 中无效

Flutter web Http post请求无法使用http包