如何使用java.net.URLConnection来触发和处理HTTP请求

时间:2010-05-08 06:16:12

标签: java http httprequest httpurlconnection urlconnection

此处经常询问java.net.URLConnection的使用情况,而Oracle tutorial 简明扼要。

该教程基本上只显示如何触发GET请求并读取响应。它没有解释如何使用它来执行POST请求,设置请求标头,读取响应标头,处理cookie,提交HTML表单,上传文件等。

那么,我如何使用java.net.URLConnection来触发和处理“高级”HTTP请求?

11 个答案:

答案 0 :(得分:2629)

答案 1 :(得分:88)

使用HTTP时,引用HttpURLConnection而不是基类URLConnection几乎总是更有用(因为URLConnection是一个抽象类,当你要求URLConnection.openConnection()时在HTTP URL上,无论如何你都会得到它。)

然后你可以而不是依赖URLConnection#setDoOutput(true)来隐式地将请求方法设置为 POST 而不是httpURLConnection.setRequestMethod("POST")有些人可能会发现更自然(这也允许你指定其他请求方法,例如 PUT DELETE ,...)。

它还提供了有用的HTTP常量,因此您可以执行以下操作:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

答案 2 :(得分:50)

受到关于SO的这个问题和其他问题的启发,我创建了一个最小的开源basic-http-client,它体现了这里发现的大部分技术。

google-http-java-client也是一个很好的开源资源。

答案 3 :(得分:23)

使用HTTP URL Hits有两个选项:GET / POST

GET请求: -

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url";
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
System.out.println(String.valueOf(http_conn.getResponseCode()));

POST请求: -

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url"
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
http_conn.setDoOutput(true);
PrintWriter out = new PrintWriter(http_conn.getOutputStream());
if (urlparameter != null) {
   out.println(urlparameter);
}
out.close();
out = null;
System.out.println(String.valueOf(http_conn.getResponseCode()));

答案 4 :(得分:21)

我建议您查看kevinsawicki/http-request上的代码,它基本上是HttpUrlConnection之上的包装器,它提供了一个更简单的API,以防您只是想立即发出请求或者您可以看看来源(它不是太大)来看看如何处理连接。

示例:发出内容类型为GET的{​​{1}}请求和一些查询参数:

application/json

答案 5 :(得分:20)

我也对这种反应非常鼓舞。

我经常在我需要做一些HTTP的项目上,我可能不想引入很多第三方依赖项(引入其他依赖项等等等)。

我开始基于这些对话开始编写我自己的实用程序(不是任何完成的地方):

package org.boon.utils;


import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;

import static org.boon.utils.IO.read;

public class HTTP {

然后只有一堆或静态的方法。

public static String get(
        final String url) {

    Exceptions.tryIt(() -> {
        URLConnection connection;
        connection = doGet(url, null, null, null);
        return extractResponseString(connection);
    });
    return null;
}

public static String getWithHeaders(
        final String url,
        final Map<String, ? extends Object> headers) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, null, null);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

public static String getWithContentType(
        final String url,
        final Map<String, ? extends Object> headers,
        String contentType) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, contentType, null);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}
public static String getWithCharSet(
        final String url,
        final Map<String, ? extends Object> headers,
        String contentType,
        String charSet) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, contentType, charSet);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

然后张贴......

public static String postBody(
        final String url,
        final String body) {
    URLConnection connection;
    try {
        connection = doPost(url, null, "text/plain", null, body);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

public static String postBodyWithHeaders(
        final String url,
        final Map<String, ? extends Object> headers,
        final String body) {
    URLConnection connection;
    try {
        connection = doPost(url, headers, "text/plain", null, body);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}



public static String postBodyWithContentType(
        final String url,
        final Map<String, ? extends Object> headers,
        final String contentType,
        final String body) {

    URLConnection connection;
    try {
        connection = doPost(url, headers, contentType, null, body);


        return extractResponseString(connection);


    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }


}


public static String postBodyWithCharset(
        final String url,
        final Map<String, ? extends Object> headers,
        final String contentType,
        final String charSet,
        final String body) {

    URLConnection connection;
    try {
        connection = doPost(url, headers, contentType, charSet, body);


        return extractResponseString(connection);


    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }


}

private static URLConnection doPost(String url, Map<String, ? extends Object> headers,
                                    String contentType, String charset, String body
                                    ) throws IOException {
    URLConnection connection;/* Handle output. */
    connection = new URL(url).openConnection();
    connection.setDoOutput(true);
    manageContentTypeHeaders(contentType, charset, connection);

    manageHeaders(headers, connection);


    IO.write(connection.getOutputStream(), body, IO.CHARSET);
    return connection;
}

private static void manageHeaders(Map<String, ? extends Object> headers, URLConnection connection) {
    if (headers != null) {
        for (Map.Entry<String, ? extends Object> entry : headers.entrySet()) {
            connection.setRequestProperty(entry.getKey(), entry.getValue().toString());
        }
    }
}

private static void manageContentTypeHeaders(String contentType, String charset, URLConnection connection) {
    connection.setRequestProperty("Accept-Charset", charset == null ? IO.CHARSET : charset);
    if (contentType!=null && !contentType.isEmpty()) {
        connection.setRequestProperty("Content-Type", contentType);
    }
}

private static URLConnection doGet(String url, Map<String, ? extends Object> headers,
                                    String contentType, String charset) throws IOException {
    URLConnection connection;/* Handle output. */
    connection = new URL(url).openConnection();
    manageContentTypeHeaders(contentType, charset, connection);

    manageHeaders(headers, connection);

    return connection;
}

private static String extractResponseString(URLConnection connection) throws IOException {
/* Handle input. */
    HttpURLConnection http = (HttpURLConnection)connection;
    int status = http.getResponseCode();
    String charset = getCharset(connection.getHeaderField("Content-Type"));

    if (status==200) {
        return readResponseBody(http, charset);
    } else {
        return readErrorResponseBody(http, status, charset);
    }
}

private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) {
    InputStream errorStream = http.getErrorStream();
    if ( errorStream!=null ) {
        String error = charset== null ? read( errorStream ) :
            read( errorStream, charset );
        throw new RuntimeException("STATUS CODE =" + status + "\n\n" + error);
    } else {
        throw new RuntimeException("STATUS CODE =" + status);
    }
}

private static String readResponseBody(HttpURLConnection http, String charset) throws IOException {
    if (charset != null) {
        return read(http.getInputStream(), charset);
    } else {
        return read(http.getInputStream());
    }
}

private static String getCharset(String contentType) {
    if (contentType==null)  {
        return null;
    }
    String charset = null;
    for (String param : contentType.replace(" ", "").split(";")) {
        if (param.startsWith("charset=")) {
            charset = param.split("=", 2)[1];
            break;
        }
    }
    charset = charset == null ?  IO.CHARSET : charset;

    return charset;
}

嗯,你明白了......

以下是测试:

static class MyHandler implements HttpHandler {
    public void handle(HttpExchange t) throws IOException {

        InputStream requestBody = t.getRequestBody();
        String body = IO.read(requestBody);
        Headers requestHeaders = t.getRequestHeaders();
        body = body + "\n" + copy(requestHeaders).toString();
        t.sendResponseHeaders(200, body.length());
        OutputStream os = t.getResponseBody();
        os.write(body.getBytes());
        os.close();
    }
}


@Test
public void testHappy() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9212), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBodyWithContentType("http://localhost:9212/test", headers, "text/plain", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));


    response = HTTP.postBodyWithCharset("http://localhost:9212/test", headers, "text/plain", "UTF-8", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    response = HTTP.postBodyWithHeaders("http://localhost:9212/test", headers, "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));


    response = HTTP.get("http://localhost:9212/test");

    System.out.println(response);


    response = HTTP.getWithHeaders("http://localhost:9212/test", headers);

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));



    response = HTTP.getWithContentType("http://localhost:9212/test", headers, "text/plain");

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));



    response = HTTP.getWithCharSet("http://localhost:9212/test", headers, "text/plain", "UTF-8");

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    Thread.sleep(10);

    server.stop(0);


}

@Test
public void testPostBody() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9220), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBody("http://localhost:9220/test", "hi mom");

    assertTrue(response.contains("hi mom"));


    Thread.sleep(10);

    server.stop(0);


}

@Test(expected = RuntimeException.class)
public void testSad() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9213), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBodyWithContentType("http://localhost:9213/foo", headers, "text/plain", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    Thread.sleep(10);

    server.stop(0);


}

你可以在这里找到其余部分:

https://github.com/RichardHightower/boon

我的目标是以更简单的方式提供想要做的常见事情....

答案 6 :(得分:20)

更新

  

新的HTTP客户端随Java 9一起提供,但作为一部分   孵化器模块名为jdk.incubator.httpclient。孵化器模块是   一种将非最终API放在开发人员手中的方法   API将在未来完成或删除   释放。

在Java 9中,您可以发送GET请求,例如:

// GET
HttpResponse response = HttpRequest
    .create(new URI("http://www.stackoverflow.com"))
    .headers("Foo", "foovalue", "Bar", "barvalue")
    .GET()
    .response();

然后您可以检查返回的HttpResponse

int statusCode = response.statusCode();
String responseBody = response.body(HttpResponse.asString());

由于这个新的HTTP客户端位于 java.httpclient jdk.incubator.httpclient模块中,因此您应该在module-info.java文件中声明此依赖关系:

module com.foo.bar {
    requires jdk.incubator.httpclient;
}

答案 7 :(得分:16)

最初我被这个article误导了HttpClient

后来我意识到HttpURLConnection将会留在article

根据Google博客

  

Apache HTTP客户端在Eclair和Froyo上的错误更少。它是这些版本的最佳选择。对于Gingerbread,HttpURLConnection是最佳选择。它简单的API和小巧的尺寸使其非常适合Android。

     

透明压缩和响应缓存可减少网络使用,提高速度并节省电池电量。新的应用程序应该使用HttpURLConnection;这是我们将继续投入精力的地方。

在阅读this article和其他一些堆叠问题之后,我确信HttpURLConnection将会持续更长时间。

有些赞成HttpURLConnections的SE问题:

On Android, make a POST request with URL Encoded Form data without using UrlEncodedFormEntity

HttpPost works in Java project, not in Android

答案 8 :(得分:13)

您还可以使用JdkRequest中的jcabi-http(我是开发人员),它可以为您完成所有这些工作,解析HttpURLConnection,触发HTTP请求并解析响应,例如:

String html = new JdkRequest("http://www.google.com").fetch().body();

查看此博文以获取更多信息:http://www.yegor256.com/2014/04/11/jcabi-http-intro.html

答案 9 :(得分:13)

还有OkHttp,这是一个默认有效的HTTP客户端:

  
      
  • HTTP / 2支持允许对同一主机的所有请求共享套接字。
  •   
  • 连接池减少了请求延迟(如果HTTP / 2不可用)。
  •   
  • 透明GZIP缩小了下载大小。
  •   
  • 响应缓存可以完全避免网络重复请求。
  •   

首先创建OkHttpClient的实例:

OkHttpClient client = new OkHttpClient();

然后,准备好GET请求:

Request request = new Request.Builder()
      .url(url)
      .build();

最后,使用OkHttpClient发送准备好的Request

Response response = client.newCall(request).execute();

有关详细信息,请参阅OkHttp's documentation

答案 10 :(得分:11)

如果您使用的是http,请删除此行

urlConnection.setDoOutput(true);