使用 Json 的 HTTP POST on Body-Flutter/Dart

这是我向 API 发出请求的代码:

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;


Future<http.Response> postRequest () async {
var url ='https://pae.ipportalegre.pt/testes2/wsjson/api/app/ws-authenticate';
var body = jsonEncode({ 'data': { 'apikey': '12345678901234567890' } });


print("Body: " + body);


http.post(url,
headers: {"Content-Type": "application/json"},
body: body
).then((http.Response response) {
print("Response status: ${response.statusCode}");
print("Response body: ${response.contentLength}");
print(response.headers);
print(response.request);


});
}

我在请求的响应中遇到了一个问题,它假设有一个带 json 的 body,但是出了问题,我认为是我发送给 body 请求的 json 出了问题,因为它是一个嵌套的 json 对象,键的值是一个 json 对象。我很想知道如何正确地解析 json 并将其插入到请求的正文中。

这是头部响应:

 {set-cookie: JSESSIONID=DA65FBCBA2796D173F8C8D78AD87F9AD;path=/testes2/;HttpOnly, last-modified: Thu, 10 May 2018 17:15:13 GMT, cache-control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0, date: Thu, 10 May 2018 17:15:13 GMT, content-length: 0, pragma: no-cache, content-type: text/html, server: Apache-Coyote/1.1, expires: Tue, 03 Jul 2001 06:00:00 GMT}

应该是这样的:

Server: Apache-Coyote/1.1
Expires: Tue, 03 Jul 2001 06:00:00 GMT
Last-Modified: Thu, 10 May 2018 17:17:07 GMT
Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0
Pragma: no-cache
Content-Type: application/json;charset=UTF-8
Vary: Accept-Encoding
Set-Cookie: JSESSIONID=84813CC68E0E8EA6021CB0B4C2F245BC;path=/testes2/;HttpOnly
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked

主体响应是空的,我认为这是因为主体我发送的请求,有人能帮助我嵌套的 json 对象的价值? ?

邮递员截图:

176338 次浏览

OK, finally we have an answer...

You are correctly specifying headers: {"Content-Type": "application/json"}, to set your content type. Under the hood either the package http or the lower level dart:io HttpClient is changing this to application/json; charset=utf-8. However, your server web application obviously isn't expecting the suffix.

To prove this I tried it in Java, with the two versions

conn.setRequestProperty("content-type", "application/json; charset=utf-8"); // fails
conn.setRequestProperty("content-type", "application/json"); // works

Are you able to contact the web application owner to explain their bug? I can't see where Dart is adding the suffix, but I'll look later.

EDIT Later investigation shows that it's the http package that, while doing a lot of the grunt work for you, is adding the suffix that your server dislikes. If you can't get them to fix the server then you can by-pass http and use the dart:io HttpClient directly. You end up with a bit of boilerplate which is normally handled for you by http.

Working example below:

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


main() async {
String url =
'https://pae.ipportalegre.pt/testes2/wsjson/api/app/ws-authenticate';
Map map = {
'data': {'apikey': '12345678901234567890'},
};


print(await apiRequest(url, map));
}


Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
// todo - you should check the response.statusCode
String reply = await response.transform(utf8.decoder).join();
httpClient.close();
return reply;
}

Depending on your use case, it may be more efficient to re-use the HttpClient, rather than keep creating a new one for each request. Todo - add some error handling ;-)

This would also work :

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


sendRequest() async {


Map data = {
'apikey': '12345678901234567890'
};


var url = 'https://pae.ipportalegre.pt/testes2/wsjson/api/app/ws-authenticate';
http.post(url, body: data)
.then((response) {
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
});
}

This works!

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;


Future<http.Response> postRequest () async {
var url ='https://pae.ipportalegre.pt/testes2/wsjson/api/app/ws-authenticate';


Map data = {
'apikey': '12345678901234567890'
}
//encode Map to JSON
var body = json.encode(data);


var response = await http.post(url,
headers: {"Content-Type": "application/json"},
body: body
);
print("${response.statusCode}");
print("${response.body}");
return response;
}

This one is for using HTTPClient class

 request.headers.add("body", json.encode(map));

I attached the encoded json body data to the header and added to it. It works for me.

I think many people have problems with Post 'Content-type': 'application / json' The problem here is parse data Map <String, dynamic> to json:

Hope the code below can help someone

Model:

class ConversationReq {
String name = '';
String description = '';
String privacy = '';
String type = '';
String status = '';


String role;
List<String> members;
String conversationType = '';


ConversationReq({this.type, this.name, this.status, this.description, this.privacy, this.conversationType, this.role, this.members});


Map<String, dynamic> toJson() {


final Map<String, dynamic> data = new Map<String, dynamic>();


data['name'] = this.name;
data['description'] = this.description;
data['privacy'] = this.privacy;
data['type'] = this.type;


data['conversations'] = [
{
"members": members,
"conversationType": conversationType,
}
];


return data;
}
}

Request:

createNewConversation(ConversationReq param) async {
HeaderRequestAuth headerAuth = await getAuthHeader();
var headerRequest = headerAuth.toJson();
/*
{
'Content-type': 'application/json',
'x-credential-session-token': xSectionToken,
'x-user-org-uuid': xOrg,
}
*/


var bodyValue = param.toJson();


var bodydata = json.encode(bodyValue);// important
print(bodydata);


final response = await http.post(env.BASE_API_URL + "xxx", headers: headerRequest, body: bodydata);


print(json.decode(response.body));
if (response.statusCode == 200) {
// TODO
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load ConversationRepo');
}
}

I implement like this:

static createUserWithEmail(String username, String email, String password) async{
var url = 'http://www.yourbackend.com/'+ "users";
var body = {
'user' : {
'username': username,
'address': email,
'password': password
}
};


return http.post(
url,
body: json.encode(body),
headers: {
"Content-Type": "application/json"
},
encoding: Encoding.getByName("utf-8")
);
}

In my case I forgot to enable

app.use(express.json());

in my NodeJs server.

this works for me

String body = json.encode(parameters);


http.Response response = await http.post(
url: 'https://example.com',
headers: {"Content-Type": "application/json"},
body: body,
);

In my case POST in the Flutter App is working on the Web, but not on Android devices or the emulator.

Flutter->Server->API

To fix it, I:

  1. changed HTTP HEADER on server with:

    $curlArr[CURLOPT_HTTPHEADER] = str_replace("application/x-www-form-urlencoded; charset=utf-8",
    "application/x-www-form-urlencoded",$curlArr[CURLOPT_HTTPHEADER]);
    
  2. copied most of the Headers to my App from postman.

String body = json.encode(parameters);


http.Response response = await http.post(
url: Uri.parse('https://example.com'),
headers: {"Content-Type": "application/json"},
body: body,
);

This worked for me!

This code works for me:

static Future<LoginAPI> connectToAPI(String email, String password) async {
String apiURL = "domain/login";


Map<String, String> headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};


var body = json.encode({"email": email, "password": password});


var apiResult = await http.post(
Uri.parse(apiURL),
headers: headers,
body: body,
);


var jsonObject = json.decode(apiResult.body);
if (apiResult.statusCode >= 300) {
return jsonObject // you can mapping json object also here
} else {
return jsonObject // you can mapping json object also here
}
}

If your using freeze dont forget to encode it first. Which is probably easy to forget.

String body = json.encode(parameters.toJson()); //dont skip this one
http.Response response = await http.post(
Uri.parse(apiURL),
headers: {"Content-Type": "application/json"},
body: body,
);