Java中使用JSON进行HTTP POST

226

我想在Java中使用JSON进行简单的HTTP POST。

假设URL是www.site.com

并且它接收标记为'details'的值为{"name":"myname","age":"20"},例如。

我该如何创建POST语法?

我在JSON Javadocs中也找不到POST方法。

12个回答

193

以下是需要执行的步骤:

  1. 获取Apache HttpClient,这将使您能够进行所需的请求
  2. 使用它创建一个 HttpPost 请求并添加头信息 application/x-www-form-urlencoded
  3. 创建一个 StringEntity,您将向其中传递JSON数据
  4. 执行调用

代码大致如下(您仍需要调试并使其正常工作):

// @Deprecated HttpClient httpClient = new DefaultHttpClient();
HttpClient httpClient = HttpClientBuilder.create().build();
try {
    HttpPost request = new HttpPost("http://yoururl");
    StringEntity params = new StringEntity("details={\"name\":\"xyz\",\"age\":\"20\"} ");
    request.addHeader("content-type", "application/x-www-form-urlencoded");
    request.setEntity(params);
    HttpResponse response = httpClient.execute(request);
} catch (Exception ex) {
} finally {
    // @Deprecated httpClient.getConnectionManager().shutdown(); 
}

11
可以直接在字符串中操作,但最好将其抽象为JSONObject。如果直接在字符串中操作可能会错误地编写字符串导致语法错误。使用JSONObject可以确保序列化始终遵循正确的JSON结构。 - momo
3
原文:In principal, they are both just transmitting data. The only difference is how you process it in the server. If you have only few key-value pair then a normal POST parameter with key1=value1, key2=value2, etc is probably enough, but once your data is more complex and especially containing complex structure (nested object, arrays) you would want to start consider using JSON. Sending complex structure using a key-value pair would be very nasty and difficult to parse on the server (you could try and you'll see it right away). Still remember the day when we had to do that urgh.. it wasn't pretty..翻译:从原则上讲,它们只是传输数据的方式不同。唯一的区别在于服务器如何处理数据。如果您只有几个键值对,那么使用普通的POST参数,例如key1=value1、key2=value2等,可能已经足够了。但一旦您的数据更加复杂,特别是包含复杂结构(嵌套对象、数组),您就需要开始考虑使用JSON了。使用键值对发送复杂结构将非常麻烦且难以在服务器上解析(您可以尝试一下,马上就会发现)。我还记得那些天我们不得不这样做,真是很糟糕.... - momo
1
很高兴能够帮助!如果这正是您所寻找的,您应该接受答案,以便其他有类似问题的人可以得到良好的指引。您可以在答案上使用勾选标记。如果您还有其他问题,请告诉我。 - momo
16
内容类型不应该是'application/json'吗?'application/x-www-form-urlencoded'意味着字符串将被格式化为类似于查询字符串的格式。我看到你的做法了,你把JSON数据块作为属性的值。 - Matthew Ward
1
应该使用CloseableHttpClient替换过时的部分,它提供了一个.close()-方法。请参见https://dev59.com/1mIj5IYBdhLWcg3wBA25#20713689 - Frame91
显示剩余8条评论

105
你可以利用Gson库将你的Java类转换为JSON对象。
根据上面的例子,创建一个POJO类来表示要发送的变量。
{"name":"myname","age":"20"}
变成
class pojo1
{
   String name;
   String age;
   //generate setter and getters
}

在设置了POJO1类中的变量后,您可以使用以下代码发送该类:

String       postUrl       = "www.site.com";// put in your url
Gson         gson          = new Gson();
HttpClient   httpClient    = HttpClientBuilder.create().build();
HttpPost     post          = new HttpPost(postUrl);
StringEntity postingString = new StringEntity(gson.toJson(pojo1));//gson.tojson() converts your pojo to json
post.setEntity(postingString);
post.setHeader("Content-type", "application/json");
HttpResponse  response = httpClient.execute(post);

以下是导入内容:

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;

并且对于 GSON

import com.google.gson.Gson;

1
你好,你是如何创建httpClient对象的?它是一个接口。 - user3290180
1
是的,那是一个接口。您可以使用“HttpClient httpClient = new DefaultHttpClient();”创建一个实例。 - Prakash
2
现在已经过时了,我们必须使用HttpClient httpClient = HttpClientBuilder.create().build(); - user3290180
5
如何导入HttpClientBuilder?(注:HttpClientBuilder是一个Java类库,用于在Java中执行HTTP请求和响应。) - Esterlinkof
3
我发现在 StringUtils 构造函数中使用 ContentType 参数并传入 ContentType.APPLICATION_JSON 会更加简洁,而不是手动设置头部。 - TownCube
显示剩余3条评论

70

@momo的答案适用于Apache HttpClient,版本为4.3.1或更高版本。我正在使用JSON-Java来构建我的JSON对象:

JSONObject json = new JSONObject();
json.put("someKey", "someValue");    

CloseableHttpClient httpClient = HttpClientBuilder.create().build();

try {
    HttpPost request = new HttpPost("http://yoururl");
    StringEntity params = new StringEntity(json.toString());
    request.addHeader("content-type", "application/json");
    request.setEntity(params);
    httpClient.execute(request);
// handle response here...
} catch (Exception ex) {
    // handle exception here
} finally {
    httpClient.close();
}

我们需要显式地添加内容类型吗?下面的代码会起作用吗?entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json")); 我问这个问题是因为它对我不起作用。我正在使用httpclient-4.5.1.jar。 - Darshan Gopal R
1
@DarshanGopalR,你的使用方法似乎与我的不同。我在8年前写了这个答案,并没有测试过更新版本的httpclient。我建议尽可能遵循示例。如果需要,在新项目中可以试一下,我会更新答案。 - Leonel Sanches da Silva
1
添加内容类型,例如:StringEntity entity = new StringEntity(params.toString(), ContentType.APPLICATION_JSON); - Undertaker

19

JSONObject j = new JSONObject();j.put("name", "myname");j.put("age", "20");像这样?我怎么序列化它? - asdf007
@asdf007 只需使用 j.toString() - Alex Churchill
没错,这个连接是阻塞的。如果你只是发送一个POST请求,这可能不是什么大问题;但如果你在运行一个Web服务器,这就非常重要了。 - Alex Churchill
HttpURLConnection 链接失效了。 - Tobias Roland
你能否提供一个如何将JSON发布到请求体的示例? - user2809386

18
protected void sendJson(final String play, final String prop) {
     Thread t = new Thread() {
     public void run() {
        Looper.prepare(); //For Preparing Message Pool for the childThread
        HttpClient client = new DefaultHttpClient();
        HttpConnectionParams.setConnectionTimeout(client.getParams(), 1000); //Timeout Limit
        HttpResponse response;
        JSONObject json = new JSONObject();

            try {
                HttpPost post = new HttpPost("http://192.168.0.44:80");
                json.put("play", play);
                json.put("Properties", prop);
                StringEntity se = new StringEntity(json.toString());
                se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
                post.setEntity(se);
                response = client.execute(post);

                /*Checking response */
                if (response != null) {
                    InputStream in = response.getEntity().getContent(); //Get the data in the entity
                }

            } catch (Exception e) {
                e.printStackTrace();
                showMessage("Error", "Cannot Estabilish Connection");
            }

            Looper.loop(); //Loop in the message queue
        }
    };
    t.start();
}

9
请考虑编辑您的帖子,添加更多关于代码的解释以及为什么它可以解决问题的说明。一个主要只包含代码(即使它是有效的)的答案通常不会帮助OP理解他们的问题。 - Reeno

15

试试这段代码:

HttpClient httpClient = new DefaultHttpClient();

try {
    HttpPost request = new HttpPost("http://yoururl");
    StringEntity params =new StringEntity("details={\"name\":\"myname\",\"age\":\"20\"} ");
    request.addHeader("content-type", "application/json");
    request.addHeader("Accept","application/json");
    request.setEntity(params);
    HttpResponse response = httpClient.execute(request);

    // handle response here...
}catch (Exception ex) {
    // handle exception here
} finally {
    httpClient.getConnectionManager().shutdown();
}

谢谢!只有你的答案解决了编码问题 :) - Shrikant Ballal
@SonuDhakar 为什么你既将 application/json 作为 accept header,又将它作为 content-type 发送? - Kasun Siyambalapitiya
似乎DefaultHttpClient已经被弃用。 - sdgfsdh

13

我发现这个问题是在寻找如何从Java客户端向Google终端发送POST请求的解决方案。上面的答案很可能是正确的,但在Google终端的情况下不起作用。

Google终端的解决方案。

  1. 请求正文必须只包含JSON字符串,而不是名称=值对。
  2. 内容类型标头必须设置为"application/json"。

post("http://localhost:8888/_ah/api/langapi/v1/createLanguage",
                   "{\"language\":\"russian\", \"description\":\"dsfsdfsdfsdfsd\"}");



public static void post(String url, String json ) throws Exception{
  String charset = "UTF-8"; 
  URLConnection connection = new URL(url).openConnection();
  connection.setDoOutput(true); // Triggers POST.
  connection.setRequestProperty("Accept-Charset", charset);
  connection.setRequestProperty("Content-Type", "application/json;charset=" + charset);

  try (OutputStream output = connection.getOutputStream()) {
    output.write(json.getBytes(charset));
  }

  InputStream response = connection.getInputStream();
}

当然也可以使用HttpClient来完成。


11

对于Java 11,您可以使用新的HTTP客户端

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("http://localhost/api"))
    .header("Content-Type", "application/json")
    .POST(ofInputStream(() -> getClass().getResourceAsStream(
        "/some-data.json")))
    .build();

client.sendAsync(request, BodyHandlers.ofString())
    .thenApply(HttpResponse::body)
    .thenAccept(System.out::println)
    .join();

您可以使用来自 InputStreamStringFile 的出版商。使用Jackson可以将JSON转换为StringIS


11
您可以使用以下代码与Apache HTTP一起使用:
String payload = "{\"name\": \"myname\", \"age\": \"20\"}";
post.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));

response = client.execute(request);

此外,您可以创建一个JSON对象,并将字段放入该对象中,如下所示

HttpPost post = new HttpPost(URL);
JSONObject payload = new JSONObject();
payload.put("name", "myName");
payload.put("age", "20");
post.setEntity(new StringEntity(payload.toString(), ContentType.APPLICATION_JSON));

关键是要添加ContentType.APPLICATION_JSON,否则对我来说无法工作。 new StringEntity(payload, ContentType.APPLICATION_JSON) - Johnny Cage

3

Java 11标准化了HTTP客户端API,实现了HTTP/2和Web Socket,并且可以在java.net.HTTP.*找到:

String payload = "{\"name\": \"myname\", \"age\": \"20\"}";
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder(URI.create("www.site.com"))
            .header("content-type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();
    
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());

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