Java - 通过POST方法轻松发送HTTP参数

348

我已成功地使用这段代码通过 GET 方法发送了带有一些参数的 HTTP 请求。

void sendRequest(String request)
{
    // i.e.: request = "http://example.com/index.php?param1=a&param2=b&param3=c";
    URL url = new URL(request); 
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();           
    connection.setDoOutput(true); 
    connection.setInstanceFollowRedirects(false); 
    connection.setRequestMethod("GET"); 
    connection.setRequestProperty("Content-Type", "text/plain"); 
    connection.setRequestProperty("charset", "utf-8");
    connection.connect();
}
现在我可能需要通过POST方法发送参数(即param1、param2、param3),因为它们很长。我想添加一个额外的参数到该方法中(即String httpMethod)。
为了能够通过GETPOST发送参数,我应该如何尽可能地修改上面的代码?
我希望通过更改
connection.setRequestMethod("GET");
connection.setRequestMethod("POST");

使用 HttpPost 也许可以解决问题,但是参数仍然通过 GET 方法发送。

HttpURLConnection 是否有任何有用的方法可以帮助解决问题? 是否有任何有用的 Java 工具?

非常感谢任何帮助。


Post参数是发送到HTTP头部而不是URL中的。 (您的POST URL将为http://example.com/index.php - dacwe
2
Java 1.6中未定义setRequestMethod方法:http://docs.oracle.com/javase/6/docs/api/java/net/URLConnection.html - ante.sabo
2
将其转换为Http(s)UrlConnection... - Peter Kriens
扩展问题!有人知道如何将附件作为帖子参数发送吗? - therealprashant
18个回答

498

在GET请求中,参数作为URL的一部分发送。

在POST请求中,参数作为请求主体在头部之后发送。

要使用HttpURLConnection进行POST请求,您需要在打开连接后将参数写入连接。

以下代码可帮助您入门:

String urlParameters  = "param1=a&param2=b&param3=c";
byte[] postData       = urlParameters.getBytes( StandardCharsets.UTF_8 );
int    postDataLength = postData.length;
String request        = "http://example.com/index.php";
URL    url            = new URL( request );
HttpURLConnection conn= (HttpURLConnection) url.openConnection();           
conn.setDoOutput( true );
conn.setInstanceFollowRedirects( false );
conn.setRequestMethod( "POST" );
conn.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded"); 
conn.setRequestProperty( "charset", "utf-8");
conn.setRequestProperty( "Content-Length", Integer.toString( postDataLength ));
conn.setUseCaches( false );
try( DataOutputStream wr = new DataOutputStream( conn.getOutputStream())) {
   wr.write( postData );
}

41
@Alan Geleynse说:'url.openconnection()'并不会打开连接。除非你指定了一个connect()语句,否则当你写入http请求体/头并发送它时,连接才会被打开。我已经用证书尝试过这个方法。SSL握手只有在你调用connect或向服务器发送数据时才会发生。 - Ashwin
14
getBytes()使用环境的默认字符集,而不是UTF-8。 charset=utf-8必须遵循内容类型:application/x-www-form-urlencoded;charset=utf-8。 在示例中你对字节进行了两次转换,应该这样做: byte[] data = urlParameters.getData("UTF-8"); connection.getOutputStream().write(data);不需要同时关闭、刷新和断开连接。 - Peter Kriens
8
谢谢您的补充,我相信您的意思是 byte[] data = urlParameters.getBytes(Charset.forName("UTF-8")) :). - gerrytan
7
你是否忘记在结尾处加上 wr.flush(); 和 wr.close(); 了呢? - Michael
16
如果它不起作用,为什么会有这么多点赞?你需要调用conn.getResponseCode()或者conn.getInputStream(),否则不会发送任何数据。 - Imaskar
显示剩余18条评论

258
这里有一个简单的例子,它提交一个表单,然后将结果页面输出到System.out。当然,根据实际情况需要更改URL和POST参数:
import java.io.*;
import java.net.*;
import java.util.*;

class Test {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://example.net/new-message.php");
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("name", "Freddie the Fish");
        params.put("email", "fishie@seamail.example.com");
        params.put("reply_to_thread", 10394);
        params.put("message", "Shark attacks in Botany Bay have gotten out of control. We need more defensive dolphins to protect the schools here, but Mayor Porpoise is too busy stuffing his snout with lobsters. He's so shellfish.");

        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String,Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);
        conn.getOutputStream().write(postDataBytes);

        Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

        for (int c; (c = in.read()) >= 0;)
            System.out.print((char)c);
    }
}

如果您想将结果作为String而非直接输出,请执行以下操作:
        StringBuilder sb = new StringBuilder();
        for (int c; (c = in.read()) >= 0;)
            sb.append((char)c);
        String response = sb.toString();

4
很遗憾,这段代码假定内容的编码为 UTF-8,但并非总是如此。要获取字符集,应获取标题 Content-Type 并解析其中的字符集。当该标题不可用时,请使用标准的 http 字符集:ISO-8859-1 - engineercoding
@Aprel IFTFY… 在求值过程中使用具有副作用的表达式确实很丑陋。 - user719662
1
@engineercoding 对于HTML来说,要完全正确地处理它比这更难,因为文档中可能还有Unicode BOM,或者需要解析的<meta charset="..."><meta http-equiv="Content-Type" content="...">头。 - Boann
1
@Nepster 不要这样做。response += line;非常慢,而且会吃掉换行符。我在答案中添加了一个获取字符串响应的示例。 - Boann
我们需要执行 conn.getOutputStream().flush() 吗? - Shubham AgaRwal
显示剩余3条评论

66

我无法实现Alan的示例来进行发布,所以最终得到了这个:

String urlParameters = "param1=a&param2=b&param3=c";
URL url = new URL("http://example.com/index.php");
URLConnection conn = url.openConnection();

conn.setDoOutput(true);

OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());

writer.write(urlParameters);
writer.flush();

String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

while ((line = reader.readLine()) != null) {
    System.out.println(line);
}
writer.close();
reader.close();         

1
很遗憾,这段代码没有读取响应。它读取了空的表单HTML。 - Kovács Imre
我需要在Alan的示例中添加打开响应流的代码。在此之前,没有任何字节被发送。 - beefeather
1
我把writer.close()调用删除掉就解决了。 - Maxime T

25

我发现使用HttpURLConnection非常繁琐。你需要编写大量样板代码,容易出错。我需要一个轻量级的封装库来简化我的Android项目,于是开发了一个库供您使用:DavidWebb

上面的示例可以这样编写:

Webb webb = Webb.create();
webb.post("http://example.com/index.php")
        .param("param1", "a")
        .param("param2", "b")
        .param("param3", "c")
        .ensureSuccess()
        .asVoid();
您可以在提供的链接中找到备选库列表。

2
我不会点赞,因为你的帖子更像是广告而不是答案...但是,我尝试使用了你的库,我很喜欢它。非常简洁;有很多语法糖;如果你像我一样将Java用作脚本语言,那么这是一个非常快速和高效地添加一些http交互的好库。零样板代码有时很有价值,对于OP可能也有用。 - Dean
3
我会给你点赞。我已成功地在我的一个应用程序中使用了DavidWebb,并将在不久将来为另外两个应用程序使用。非常容易使用。 - William T. Mallard
谢谢,使用DefaultHttpClient在Android上使用https失败并出现SSLPeerUnverifiedException:没有对等证书(即使是正确签名的https证书),使用URL很麻烦(编码参数,检查结果)。对我来说,使用DavidWebb很有效,感谢。 - Martin Vysny
没有AsyncTask支持?所以默认情况下锁定UI线程...那很糟糕。 - slinden77
这是一个非常基础的库。程序员必须从后台线程中调用它,在AsyncTask、IntentService、同步处理程序等中使用。而且它不依赖于Android->也可以在Java SE和EE中使用。 - hgoebl

14
import java.net.*;

public class Demo{

  public static void main(){

       String data = "data=Hello+World!";
       URL url = new URL("http://localhost:8084/WebListenerServer/webListener");
       HttpURLConnection con = (HttpURLConnection) url.openConnection();
       con.setRequestMethod("POST");
       con.setDoOutput(true);
       con.getOutputStream().write(data.getBytes("UTF-8"));
       con.getInputStream();

    }

}

6
这句话的意思是“这是什么鬼,import java.net.*;!”其中,“import”是导入库的关键字,“java.net.*”表示导入Java中网络相关的所有类。 - Yousha Aleayoub

12

我已经阅读了上面的答案并创建了一个实用类来简化HTTP请求。希望它能对你有所帮助。

方法调用

  // send params with Hash Map
    HashMap<String, String> params = new HashMap<String, String>();
    params.put("email","me@example.com");
    params.put("password","12345");

    //server url
    String url = "http://www.example.com";

    // static class "HttpUtility" with static method "newRequest(url,method,callback)"
    HttpUtility.newRequest(url,HttpUtility.METHOD_POST,params, new HttpUtility.Callback() {
        @Override
        public void OnSuccess(String response) {
        // on success
           System.out.println("Server OnSuccess response="+response);
        }
        @Override
        public void OnError(int status_code, String message) {
        // on error
              System.out.println("Server OnError status_code="+status_code+" message="+message);
        }
    });

实用类

import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
import static java.net.HttpURLConnection.HTTP_OK;

public class HttpUtility {

 public static final int METHOD_GET = 0; // METHOD GET
 public static final int METHOD_POST = 1; // METHOD POST

 // Callback interface
 public interface Callback {
  // abstract methods
  public void OnSuccess(String response);
  public void OnError(int status_code, String message);
 }
 // static method
 public static void newRequest(String web_url, int method, HashMap < String, String > params, Callback callback) {

  // thread for handling async task
  new Thread(new Runnable() {
   @Override
   public void run() {
    try {
     String url = web_url;
     // write GET params,append with url
     if (method == METHOD_GET && params != null) {
      for (Map.Entry < String, String > item: params.entrySet()) {
       String key = URLEncoder.encode(item.getKey(), "UTF-8");
       String value = URLEncoder.encode(item.getValue(), "UTF-8");
       if (!url.contains("?")) {
        url += "?" + key + "=" + value;
       } else {
        url += "&" + key + "=" + value;
       }
      }
     }

     HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
     urlConnection.setUseCaches(false);
     urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); // handle url encoded form data
     urlConnection.setRequestProperty("charset", "utf-8");
     if (method == METHOD_GET) {
      urlConnection.setRequestMethod("GET");
     } else if (method == METHOD_POST) {
      urlConnection.setDoOutput(true); // write POST params
      urlConnection.setRequestMethod("POST");
     }

     //write POST data 
     if (method == METHOD_POST && params != null) {
      StringBuilder postData = new StringBuilder();
      for (Map.Entry < String, String > item: params.entrySet()) {
       if (postData.length() != 0) postData.append('&');
       postData.append(URLEncoder.encode(item.getKey(), "UTF-8"));
       postData.append('=');
       postData.append(URLEncoder.encode(String.valueOf(item.getValue()), "UTF-8"));
      }
      byte[] postDataBytes = postData.toString().getBytes("UTF-8");
      urlConnection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
      urlConnection.getOutputStream().write(postDataBytes);

     }
     // server response code
     int responseCode = urlConnection.getResponseCode();
     if (responseCode == HTTP_OK && callback != null) {
      BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
      StringBuilder response = new StringBuilder();
      String line;
      while ((line = reader.readLine()) != null) {
       response.append(line);
      }
      // callback success
      callback.OnSuccess(response.toString());
      reader.close(); // close BufferReader
     } else if (callback != null) {
      // callback error
      callback.OnError(responseCode, urlConnection.getResponseMessage());
     }

     urlConnection.disconnect(); // disconnect connection
    } catch (IOException e) {
     e.printStackTrace();
     if (callback != null) {
      // callback error
      callback.OnError(500, e.getLocalizedMessage());
     }
    }
   }
  }).start(); // start thread
 }
}

10

我看到其他答案已经给出了替代方案,我个人认为你直觉上做得对 ;). 很抱歉,在devoxx这里有几位演讲者一直在抨击这种事情。

这就是为什么我个人使用Apache的HTTPClient/HttpCore库来完成这样的工作,我发现它们的API比Java本地的HTTP支持更易于使用。当然,你的情况可能不同!


6

GET和POST方法设置如下... 有两种用于API调用的类型,分别为1)get()和2)post()。使用get()方法从API JSON数组中获取值并使用post()方法在URL中发布我们的数据并获取响应。

 public class HttpClientForExample {

    private final String USER_AGENT = "Mozilla/5.0";

    public static void main(String[] args) throws Exception {

        HttpClientExample http = new HttpClientExample();

        System.out.println("Testing 1 - Send Http GET request");
        http.sendGet();

        System.out.println("\nTesting 2 - Send Http POST request");
        http.sendPost();

    }

    // HTTP GET request
    private void sendGet() throws Exception {

        String url = "http://www.google.com/search?q=developer";

        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url);

        // add request header
        request.addHeader("User-Agent", USER_AGENT);

        HttpResponse response = client.execute(request);

        System.out.println("\nSending 'GET' request to URL : " + url);
        System.out.println("Response Code : " + 
                       response.getStatusLine().getStatusCode());

        BufferedReader rd = new BufferedReader(
                       new InputStreamReader(response.getEntity().getContent()));

        StringBuffer result = new StringBuffer();
        String line = "";
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }

        System.out.println(result.toString());

    }

    // HTTP POST request
    private void sendPost() throws Exception {

        String url = "https://selfsolve.apple.com/wcResults.do";

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);

        // add header
        post.setHeader("User-Agent", USER_AGENT);

        List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
        urlParameters.add(new BasicNameValuePair("sn", "C02G8416DRJM"));
        urlParameters.add(new BasicNameValuePair("cn", ""));
        urlParameters.add(new BasicNameValuePair("locale", ""));
        urlParameters.add(new BasicNameValuePair("caller", ""));
        urlParameters.add(new BasicNameValuePair("num", "12345"));

        post.setEntity(new UrlEncodedFormEntity(urlParameters));

        HttpResponse response = client.execute(post);
        System.out.println("\nSending 'POST' request to URL : " + url);
        System.out.println("Post parameters : " + post.getEntity());
        System.out.println("Response Code : " + 
                                    response.getStatusLine().getStatusCode());

        BufferedReader rd = new BufferedReader(
                        new InputStreamReader(response.getEntity().getContent()));

        StringBuffer result = new StringBuffer();
        String line = "";
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }

        System.out.println(result.toString());

    }

}

4

我也遇到了同样的问题。我想通过POST方式发送数据。 我使用了以下代码:

    URL url = new URL("http://example.com/getval.php");
    Map<String,Object> params = new LinkedHashMap<>();
    params.put("param1", param1);
    params.put("param2", param2);

    StringBuilder postData = new StringBuilder();
    for (Map.Entry<String,Object> param : params.entrySet()) {
        if (postData.length() != 0) postData.append('&');
        postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
        postData.append('=');
        postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
    }
    String urlParameters = postData.toString();
    URLConnection conn = url.openConnection();

    conn.setDoOutput(true);

    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());

    writer.write(urlParameters);
    writer.flush();

    String result = "";
    String line;
    BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));

    while ((line = reader.readLine()) != null) {
        result += line;
    }
    writer.close();
    reader.close()
    System.out.println(result);

我使用Jsoup进行解析:

    Document doc = Jsoup.parseBodyFragment(value);
    Iterator<Element> opts = doc.select("option").iterator();
    for (;opts.hasNext();) {
        Element item = opts.next();
        if (item.hasAttr("value")) {
            System.out.println(item.attr("value"));
        }
    }

3

尝试使用这个模式:

public static PricesResponse getResponse(EventRequestRaw request) {

    // String urlParameters  = "param1=a&param2=b&param3=c";
    String urlParameters = Piping.serialize(request);

    HttpURLConnection conn = RestClient.getPOSTConnection(endPoint, urlParameters);

    PricesResponse response = null;

    try {
        // POST
        OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
        writer.write(urlParameters);
        writer.flush();

        // RESPONSE
        BufferedReader reader = new BufferedReader(new InputStreamReader((conn.getInputStream()), StandardCharsets.UTF_8));
        String json = Buffering.getString(reader);
        response = (PricesResponse) Piping.deserialize(json, PricesResponse.class);

        writer.close();
        reader.close();

    } catch (Exception e) {
        e.printStackTrace();
    }

    conn.disconnect();

    System.out.println("PricesClient: " + response.toString());

    return response;
}

public static HttpURLConnection getPOSTConnection(String endPoint, String urlParameters) {

    return RestClient.getConnection(endPoint, "POST", urlParameters);

}


public static HttpURLConnection getConnection(String endPoint, String method, String urlParameters) {

    System.out.println("ENDPOINT " + endPoint + " METHOD " + method);
    HttpURLConnection conn = null;

    try {
        URL url = new URL(endPoint);
        conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "text/plain");

    } catch (IOException e) {
        e.printStackTrace();
    }

    return conn;
}

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