java.net.URLConnection을 사용하여 HTTP 요청을 시작하고 처리하는 방법은 무엇입니까?


1947

java.net.URLConnection여기서는 자주 사용에 대한 질문이 있으며 Oracle 자습서너무 간결합니다.

이 튜토리얼은 기본적으로 GET 요청을 실행하고 응답을 읽는 방법 만 보여줍니다. POST 요청 수행, 요청 헤더 설정, 응답 헤더 읽기, 쿠키 처리, HTML 양식 제출, 파일 업로드 등을 사용하는 방법을 설명하지 않습니다.

그렇다면 어떻게 java.net.URLConnection"고급"HTTP 요청을 시작하고 처리 할 수 있습니까?

답변:


2711

먼저 고지 사항 : 게시 된 코드 스 니펫은 모두 기본 예입니다. 당신은 사소한 처리해야합니다 IOExceptions와 RuntimeException같은 S NullPointerException, ArrayIndexOutOfBoundsException및 배우자들 자신을.


준비중

먼저 URL과 문자셋을 알아야합니다. 매개 변수는 선택 사항이며 기능 요구 사항에 따라 다릅니다.

String url = "http://example.com";
String charset = "UTF-8";  // Or in Java 7 and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name()
String param1 = "value1";
String param2 = "value2";
// ...

String query = String.format("param1=%s&param2=%s", 
     URLEncoder.encode(param1, charset), 
     URLEncoder.encode(param2, charset));

쿼리 매개 변수는 name=value형식 이어야 하고로 연결 해야합니다 &. 일반적 으로을 사용하여 쿼리 매개 변수를 지정된 문자 세트로 URL 인코딩 합니다 URLEncoder#encode().

String#format()단지 편의를위한 것입니다. String 연결 연산자 +가 두 번 이상 필요할 때 선호합니다 .


(선택적) 쿼리 매개 변수를 사용 하여 HTTP GET 요청 실행

사소한 일입니다. 기본 요청 방법입니다.

URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...

모든 쿼리 문자열은을 사용하여 URL에 연결해야합니다 ?. Accept-Charset당신이 어떤 쿼리 문자열을 전송하지 않는 경우 헤더는.에있는 매개 변수를 인코딩하는 어떤 서버를 암시 할 수 있습니다 당신은 떠날 수 Accept-Charset멀리 헤더를. 헤더를 설정할 필요가 없으면 URL#openStream()바로 가기 방법을 사용할 수도 있습니다 .

InputStream response = new URL(url).openStream();
// ...

다른 쪽이 어느 쪽의 경우는 HttpServlet, 다음의 doGet()방법은 호출 될 상기 파라미터에 의해 가능한 것이다 HttpServletRequest#getParameter().

테스트 목적으로 다음과 같이 응답 본문을 stdout에 인쇄 할 수 있습니다.

try (Scanner scanner = new Scanner(response)) {
    String responseBody = scanner.useDelimiter("\\A").next();
    System.out.println(responseBody);
}

쿼리 매개 변수를 사용 하여 HTTP POST 요청 실행

로 설정하면 요청 메소드 URLConnection#setDoOutput()true내재적으로 POST로 설정됩니다. 웹 양식처럼 표준 HTTP POST application/x-www-form-urlencoded는 쿼리 문자열이 요청 본문에 기록되는 유형 입니다.

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);

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

InputStream response = connection.getInputStream();
// ...

참고 : 프로그래밍 방식으로 HTML 양식을 제출할 때마다 요소 name=value쌍을 <input type="hidden">쿼리 문자열로 가져 가야합니다. 물론 프로그래밍 방식으로 "누르고 싶은"요소 name=value쌍 도 잊지 마십시오. <input type="submit">이는 일반적으로 서버 측에서 버튼을 눌렀는지 여부와 구별하는 데 사용됩니다 (있는 경우).

또한 얻어진 캐스트 할 수 있습니다 URLConnectionHttpURLConnection와를 사용하는 HttpURLConnection#setRequestMethod()대신. 그러나 출력에 연결을 사용하려는 경우 여전히로 설정 URLConnection#setDoOutput()해야 true합니다.

HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...

다른 쪽이 어느 쪽의 경우는 HttpServlet, 다음의 doPost()방법은 호출 될 상기 파라미터에 의해 가능한 것이다 HttpServletRequest#getParameter().


실제로 HTTP 요청을 발생

을 사용하여 HTTP 요청을 명시 적으로 실행할 수 URLConnection#connect()있지만 요청 본문 사용 등의 HTTP 응답에 대한 정보를 얻으려는 경우 요청시 요청이 자동으로 시작 URLConnection#getInputStream()됩니다. 위의 예는 정확히 그렇게하므로 connect()호출은 실제로 불필요합니다.


HTTP 응답 정보 수집

  1. HTTP 응답 상태 :

    HttpURLConnection여기 가 필요합니다 . 필요한 경우 먼저 캐스팅하십시오.

    int status = httpConnection.getResponseCode();
  2. HTTP 응답 헤더 :

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
  3. HTTP 응답 인코딩 :

    Content-Typecharset매개 변수 가 포함 된 경우 응답 본문은 텍스트를 기반으로하며 서버 측에서 지정한 문자 인코딩으로 응답 본문을 처리하려고합니다.

    String contentType = connection.getHeaderField("Content-Type");
    String charset = null;
    
    for (String param : contentType.replace(" ", "").split(";")) {
        if (param.startsWith("charset=")) {
            charset = param.split("=", 2)[1];
            break;
        }
    }
    
    if (charset != null) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) {
            for (String line; (line = reader.readLine()) != null;) {
                // ... System.out.println(line) ?
            }
        }
    } else {
        // It's likely binary content, use InputStream/OutputStream.
    }

세션 유지

서버 측 세션은 일반적으로 쿠키에 의해 지원됩니다. 일부 웹 양식은 로그인 및 / 또는 세션에 의해 추적되어야합니다. CookieHandlerAPI를 사용하여 쿠키를 유지 관리 할 수 있습니다 . 당신은 준비 할 필요가 CookieManagerA의 CookiePolicy의를 ACCEPT_ALL모든 HTTP 요청을 보내기 전에.

// First set the default cookie manager.
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

// All the following subsequent URLConnections will use the same cookie manager.
URLConnection connection = new URL(url).openConnection();
// ...

connection = new URL(url).openConnection();
// ...

connection = new URL(url).openConnection();
// ...

모든 상황에서 항상 제대로 작동하는 것은 아닙니다. 실패하면 쿠키 헤더를 수동으로 수집하고 설정하는 것이 가장 좋습니다. 기본적으로 Set-Cookie로그인 또는 첫 번째 GET요청 의 응답에서 모든 헤더 를 가져 와서 후속 요청을 통해 전달해야합니다.

// Gather all cookies on the first request.
URLConnection connection = new URL(url).openConnection();
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
// ...

// Then use the same cookies on all subsequent requests.
connection = new URL(url).openConnection();
for (String cookie : cookies) {
    connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
}
// ...

split(";", 2)[0]같은 서버 측에 대한 무관 쿠키 속성의 존재를 제거하는 것입니다 expires, path등 또는, 당신은 또한 사용할 수 있습니다 cookie.substring(0, cookie.indexOf(';'))대신 split().


스트리밍 모드

HttpURLConnection기본적으로 의지는 버퍼 전체 실제로 관계없이 사용하여 고정 컨텐츠 길이를 직접 설정 한 여부를 보내기 전에 요청 본문을 connection.setRequestProperty("Content-Length", contentLength);. 이로 인해 OutOfMemoryException많은 POST 요청을 동시에 보낼 때마다 (예 : 파일 업로드) 이 발생할 수 있습니다 . 이를 피하기 위해을 설정하고 싶습니다 HttpURLConnection#setFixedLengthStreamingMode().

httpConnection.setFixedLengthStreamingMode(contentLength);

그러나 콘텐츠 길이를 미리 알 수없는 경우 HttpURLConnection#setChunkedStreamingMode()적절하게 설정하여 청크 스트리밍 모드를 사용할 수 있습니다 . 요청 본문이 청크로 보내질 HTTP Transfer-Encoding헤더를 설정합니다 chunked. 아래 예제는 본문을 1KB 단위로 보냅니다.

httpConnection.setChunkedStreamingMode(1024);

사용자 에이전트

요청이 예상치 못한 응답을 반환하는 반면 실제 웹 브라우저에서는 제대로 작동 할 수 있습니다 . 서버 측이 User-Agent요청 헤더를 기반으로 요청을 차단했을 수 있습니다. URLConnection기본적으로 의지로 설정 Java/1.6.0_19마지막 부분은 분명히 JRE 버전입니다. 다음과 같이이를 재정의 할 수 있습니다.

connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); // Do as if you're using Chrome 41 on Windows 7.

최신 브라우저 에서 User-Agent 문자열을 사용하십시오 .


오류 처리

HTTP 응답 코드가 4nn(클라이언트 오류) 또는 5nn(서버 오류) 인 HttpURLConnection#getErrorStream()경우 서버에서 유용한 오류 정보를 보냈는지 확인하십시오.

InputStream error = ((HttpURLConnection) connection).getErrorStream();

HTTP 응답 코드가 -1이면 연결 및 응답 처리에 문제가 있습니다. HttpURLConnection구현은 이전의 JRE에 연결을 유지 하느라 다소 버그가 있습니다. http.keepAlive시스템 속성을 로 설정하여 끌 수 있습니다 false. 응용 프로그램을 시작할 때 다음과 같이 프로그래밍 방식으로이 작업을 수행 할 수 있습니다.

System.setProperty("http.keepAlive", "false");

파일 업로드

일반적으로 multipart/form-data혼합 POST 컨텐츠 (이진 및 문자 데이터)에 인코딩을 사용 합니다. 인코딩은 RFC2388 에 더 자세히 설명되어 있습니다 .

String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (
    OutputStream output = connection.getOutputStream();
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
    // Send normal param.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF).append(param).append(CRLF).flush();

    // Send text file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
    writer.append(CRLF).flush();
    Files.copy(textFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // Send binary file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
    writer.append("Content-Transfer-Encoding: binary").append(CRLF);
    writer.append(CRLF).flush();
    Files.copy(binaryFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // End of multipart/form-data.
    writer.append("--" + boundary + "--").append(CRLF).flush();
}

다른 측면이 경우 HttpServlet, 다음의 doPost()메소드가 호출되고 부품으로 사용할 수 있습니다 HttpServletRequest#getPart()(참고, 이렇게 하지 getParameter() 등등!). getPart()방법은 비교적 새로운 그러나, 이것은 서블릿 3.0 (3 글래스 피시 톰캣 7 등)에 도입되는 것. Servlet 3.0 이전에는 Apache Commons FileUpload 를 사용하여 multipart/form-data요청 을 구문 분석하는 것이 가장 좋습니다 . FileUpload 및 Servelt 3.0 접근 방식의 예제 도이 답변 을 참조하십시오 .


신뢰할 수 없거나 잘못 구성된 HTTPS 사이트 다루기

때로는 웹 스크레이퍼를 작성하고 있기 때문에 HTTPS URL을 연결해야 할 수도 있습니다. 이 경우 javax.net.ssl.SSLException: Not trusted server certificateSSL 인증서를 최신 상태로 유지하지 않는 일부 HTTPS 사이트 java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found또는 javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name잘못 구성된 일부 HTTPS 사이트에서 문제가 발생할 수 있습니다.

static웹 스크래퍼 클래스에서 다음의 1 회 실행 초기화 프로그램은 HttpsURLConnection해당 HTTPS 사이트에 대해 보다 관대 해져 더 이상 예외를 발생시키지 않아야합니다.

static {
    TrustManager[] trustAllCertificates = new TrustManager[] {
        new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null; // Not relevant.
            }
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
        }
    };

    HostnameVerifier trustAllHostnames = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // Just allow them all.
        }
    };

    try {
        System.setProperty("jsse.enableSNIExtension", "false");
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCertificates, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
    }
    catch (GeneralSecurityException e) {
        throw new ExceptionInInitializerError(e);
    }
}

마지막 말

아파치 HttpComponents HttpClient를이 입니다 훨씬 더 편리이 모두 :)


HTML 파싱 및 추출

HTML에서 데이터를 구문 분석하고 추출하는 것만 있으면 Jsoup 과 같은 HTML 파서를 사용하는 것이 좋습니다.


119
아파치 링크를 먼저 배치해야 솔루션을 찾는 사람들이 더 빨리 찾을 수 있습니다.)
ZeissS

40
@ivanceras :이 답변의 정보를 바탕으로 끓일 수 없다면 Ask Question오른쪽 상단의 버튼을 누르십시오 .
BalusC

3
@Brais : 사양을 읽으십시오. 이 --부분은 경계 자체 의 일부가 아닙니다. 구분자 문자열 일뿐입니다. 잘못된 수정 사항을 롤백했습니다.
BalusC

7
@BalusC는 그러한 완벽한 튜토리얼에 감사드립니다. "마감 스트림 / 연결"과 같은 제목도 포함하십시오. 언제 어떤 스트림 / 연결을 닫을 지 혼란 스럽습니다.

10
슬픈 부분은 안드로이드에서 지금 아파치를 사용하는 것은 권장 하지 않으며 잔인 하다는 것입니다 . android-developers.blogspot.in/2011/09/…HttpClientHttpURLConnection
yati sagade

91

HTTP로 작업 할 때 HttpURLConnection기본 클래스보다는 참조하는 것이 거의 항상 유용합니다 URLConnection( 어쨌든 다시 얻을 HTTP URL을 URLConnection요청할 때 추상 클래스 이기 때문에 URLConnection.openConnection()).

그런 다음 URLConnection#setDoOutput(true)요청 메소드를 내재적으로 POST로 설정하는 대신 httpURLConnection.setRequestMethod("POST")일부는 더 자연스럽게 찾을 수 있습니다 ( PUT , DELETE 등의 다른 요청 메소드를 지정할 수도 있음 ).

또한 유용한 HTTP 상수를 제공하여 다음을 수행 할 수 있습니다.

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

1
setDoOutPut true는 GET을 POST로 설정하는 문제였습니다. 감사합니다
Patrick Kafka

22
당신은 당신이 OutputStream에 데이터를 기록하려는 경우 합니다 여전히 설정 setDoOutput()true그렇지 않으면 예외가 발생합니다 (심지어 경우 setRequestMethod("POST")). 명확하게하려면 설정 URLConnection#setDoOutput(true)true암시하는 POST로 요청 방법을 설정하지만 설정 httpURLConnection.setRequestMethod("POST")POST가 수행에 하지 암시 적 설정 setDoOutput()true.
Tony Chan

54

SO에 대한이 질문과 다른 질문에서 영감을 얻어 최소한의 오픈 소스 basic-http-client를 만들었습니다. 여기에있는 대부분의 기술을 구현 를 .

google-http-java-client 도 훌륭한 오픈 소스 리소스입니다.


나는 단지 같은 생각을하고있었습니다. 그러나 HTTP GET, POST 등을 수행하는 간단한 메소드로 코드를 캡슐화하는 URLConnection 코드 만 사용하는 베어 본 / 간단한 Java 라이브러리가 있으면 좋을 것입니다. 그런 다음 라이브러리를 JAR 및 외부 JAR을 원하지 않는 경우 Java 코드로 가져 오거나 사용하거나 소스 클래스 파일을 Java 프로젝트에 포함시킬 수 있습니다. 이것은 Apache 등과 같은 다른 라이브러리에서 수행 할 수 있지만 URLConnection을 사용하는 간단한 1 파일 클래스 라이브러리와 비교할 때 더 고통 스럽습니다.
David

rapidvaluesolutions.com/tech_blog/… HttpClient보다 HttpURLConnection을 선호합니다
Ravindra babu

24

kevinsawicki / http-request 의 코드를 살펴보십시오. 기본적으로 그 위에있는 래퍼 HttpUrlConnection는 요청을 원하거나 소스를 볼 수있는 경우 훨씬 간단한 API를 제공합니다 ( 연결이 처리되는 방식을 살펴보기에는 너무 크지 않습니다.

예 : GET컨텐츠 유형 application/json및 일부 쿼리 매개 변수 로 요청하십시오 .

// GET http://google.com?q=baseball%20gloves&size=100
String response = HttpRequest.get("http://google.com", true, "q", "baseball gloves", "size", 100)
        .accept("application/json")
        .body();
System.out.println("Response was: " + response);

24

HTTP URL 조회와 함께 사용할 수있는 두 가지 옵션이 있습니다. 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()));

3
실제 JSON 응답을 어떻게 볼 수 있습니까?
Sora

21

나는 또한이 반응에 매우 고무되었습니다.

나는 종종 일부 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

내 목표는 좀 더 쉬운 방법으로하고 싶었던 일반적인 일을 제공하는 것입니다.


2
doPost메소드에는 charset요청 헤더를 설정하는 데 사용되는 매개 변수가 있지만 데이터는 하드 코딩 된 charset으로 작성됩니다 IO.CHARSET. 버그?
Vit Khudenko

21

최신 정보

새로운 HTTP 클라이언트는 Java 9와 함께 제공되지만 이름이 Incubator 모듈의 일부로 제공됩니다 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;
}

1
추가 업데이트 : 모듈이 잠복기 상태가 아닙니다. 이제 jdk.incubator.httpclient가 아닌 java.net.http 입니다.
VGR

17

처음에 나는이 기사 에 호소했다 HttpClient.

나중에 나는 HttpURLConnection기사 에서 벗어날 것이라는 것을 깨달았습니다.

구글 블로그에 따르면 :

Apache HTTP 클라이언트는 Eclair 및 Froyo에서 버그가 적습니다. 이 릴리스에 가장 적합한 선택입니다. Gingerbread의 경우 HttpURLConnection이 최선의 선택입니다. 간단한 API와 작은 크기로 Android에 적합합니다.

투명한 압축 및 응답 캐싱은 네트워크 사용을 줄이고 속도를 개선하며 배터리를 절약합니다. 새로운 응용 프로그램은 HttpURLConnection을 사용해야합니다. 우리가 앞으로 에너지를 소비 할 곳입니다.

이 기사 와 흐름 질문에 대한 다른 스택을 읽은 후에 HttpURLConnection는 더 오래 지속될 것이라고 확신합니다 .

유리한 SE 질문 중 일부 HttpURLConnections:

Android에서는 UrlEncodedFormEntity를 사용하지 않고 URL 인코딩 양식 데이터로 POST 요청을 작성하십시오.

HttpPost는 Android가 아닌 Java 프로젝트에서 작동합니다.


15

기본적으로 효율적인 HTTP 클라이언트 인 OkHttp 도 있습니다 .

  • 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의 설명서를 참조하십시오.


14

당신은 또한 사용할 수 있습니다 JdkRequest에서 jcabi-HTTP (I 개발자를 해요), HttpURLConnection의 장식 예를 들어, HTTP 요청을 발사하고 응답을 구문 분석, 당신을 위해 모든 작업을 수행한다 :

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

자세한 내용은이 블로그 게시물을 확인하십시오. http://www.yegor256.com/2014/04/11/jcabi-http-intro.html


1
쿠키는 어떻게 처리합니까?
Dejell

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.