Java >> Java tutorial >  >> Tag >> HTTP

Lav en simpel HTTP-anmodning i Java

1. Oversigt

I denne hurtige selvstudie præsenterer vi en måde at udføre HTTP-anmodninger på i Java — ved at bruge den indbyggede Java-klasse HttpUrlConnection.

Bemærk, at startende med JDK 11, leverer Java en ny API til at udføre HTTP-anmodninger, som er ment som en erstatning for HttpUrlConnection, HttpClient API.

Yderligere læsning:

En guide til HTTP-cookies i Java

En hurtig og praktisk guide til HTTP-cookies i JavaLæs mere →

Udforsker den nye HTTP-klient i Java

Udforsk den nye Java HttpClient API, som giver en masse fleksibilitet og kraftfulde funktioner.Læs mere →

Web- og applikationsservere til Java

En hurtig liste over de tilgængelige web- og applikationsservere i Java. Læs mere →

2. HttpUrlConnection

HttpUrlConnection klasse giver os mulighed for at udføre grundlæggende HTTP-anmodninger uden brug af yderligere biblioteker. Alle de klasser, vi har brug for, er en del af java.net pakke.

Ulemperne ved at bruge denne metode er, at koden kan være mere besværlig end andre HTTP-biblioteker, og at den ikke giver mere avancerede funktionaliteter såsom dedikerede metoder til tilføjelse af overskrifter eller godkendelse.

3. Oprettelse af en anmodning

Vi kan oprette en HttpUrlConnection instans ved hjælp af openConnection() metoden for URL klasse. Bemærk, at denne metode kun opretter et forbindelsesobjekt, men ikke etablerer forbindelsen endnu.

HttpUrlConnection klasse bruges til alle typer anmodninger ved at indstille requestMethod attribut til en af ​​værdierne:GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Lad os oprette en forbindelse til en given URL ved hjælp af GET-metoden:

URL url = new URL("http://example.com");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");

4. Tilføjelse af anmodningsparametre

Hvis vi ønsker at tilføje parametre til en anmodning, skal vi indstille doOutput ejendom til sand , og skriv derefter en streng af formen param1=værdi¶m2=værdi til OutputStream af HttpUrlConnection eksempel:

Map<String, String> parameters = new HashMap<>();
parameters.put("param1", "val");

con.setDoOutput(true);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(ParameterStringBuilder.getParamsString(parameters));
out.flush();
out.close();

For at lette transformationen af ​​parameterkortet , har vi skrevet en hjælpeklasse kaldet ParameterStringBuilder indeholdende en statisk metode, getParamsString() , der transformerer et Kort ind i en streng af det påkrævede format:

public class ParameterStringBuilder {
    public static String getParamsString(Map<String, String> params) 
      throws UnsupportedEncodingException{
        StringBuilder result = new StringBuilder();

        for (Map.Entry<String, String> entry : params.entrySet()) {
          result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
          result.append("=");
          result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
          result.append("&");
        }

        String resultString = result.toString();
        return resultString.length() > 0
          ? resultString.substring(0, resultString.length() - 1)
          : resultString;
    }
}

5. Indstilling af anmodningsoverskrifter

Tilføjelse af overskrifter til en anmodning kan opnås ved at bruge setRequestProperty() metode:

con.setRequestProperty("Content-Type", "application/json");

For at læse værdien af ​​en header fra en forbindelse kan vi bruge getHeaderField() metode:

String contentType = con.getHeaderField("Content-Type");

6. Konfiguration af timeouts

HttpUrlConnection klasse tillader indstilling af forbindelses- og læsetimeouts. Disse værdier definerer det tidsinterval, der skal vente på, at forbindelsen til serveren er etableret, eller at data er tilgængelige til læsning.

For at indstille timeoutværdierne kan vi bruge setConnectTimeout() og setReadTimeout() metoder:

con.setConnectTimeout(5000);
con.setReadTimeout(5000);

I eksemplet satte vi begge timeout-værdier til fem sekunder.

7. Håndtering af cookies

java.net pakken indeholder klasser, der letter arbejdet med cookies, såsom CookieManager og HttpCookie .

Først at læse cookies fra et svar , kan vi hente værdien af ​​Set-cookien header og parse den til en liste over HttpCookie objekter:

String cookiesHeader = con.getHeaderField("Set-Cookie");
List<HttpCookie> cookies = HttpCookie.parse(cookiesHeader);

Dernæst vil vi føje cookies til cookie-lageret :

cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));

Lad os tjekke, om en cookie hedder brugernavn er til stede, og hvis ikke, tilføjer vi det til cookie-lageret med værdien "john":

Optional<HttpCookie> usernameCookie = cookies.stream()
  .findAny().filter(cookie -> cookie.getName().equals("username"));
if (usernameCookie == null) {
    cookieManager.getCookieStore().add(null, new HttpCookie("username", "john"));
}

Til sidst, for at føje cookies til anmodningen , skal vi indstille Cookien header, efter lukning og genåbning af forbindelsen:

con.disconnect();
con = (HttpURLConnection) url.openConnection();

con.setRequestProperty("Cookie", 
  StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Håndtering af omdirigeringer

Vi kan aktivere eller deaktivere automatisk følgende omdirigeringer for en specifik forbindelse ved at bruge setInstanceFollowRedirects() metode med true eller falsk parameter:

con.setInstanceFollowRedirects(false);

Det er også muligt at aktivere eller deaktivere automatisk omdirigering for alle forbindelser :

HttpUrlConnection.setFollowRedirects(false);

Som standard er adfærden aktiveret.

Når en anmodning returnerer en statuskode 301 eller 302, hvilket indikerer en omdirigering, kan vi hente Placeringen header og opret en ny anmodning til den nye URL:

if (status == HttpURLConnection.HTTP_MOVED_TEMP
  || status == HttpURLConnection.HTTP_MOVED_PERM) {
    String location = con.getHeaderField("Location");
    URL newUrl = new URL(location);
    con = (HttpURLConnection) newUrl.openConnection();
}

9. Læser svaret

Læsning af svaret på anmodningen kan gøres ved at parse InputStream af HttpUrlConnection forekomst.

For at udføre anmodningen kan vi bruge getResponseCode() , connect() , getInputStream() eller getOutputStream() metoder :

int status = con.getResponseCode();

Lad os endelig læse svaret på anmodningen og placere det i et indhold Streng:

BufferedReader in = new BufferedReader(
  new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    content.append(inputLine);
}
in.close();

For at lukke forbindelsen , kan vi bruge disconnect() metode:

con.disconnect();

10. Læsning af svaret på mislykkede anmodninger

Hvis anmodningen mislykkes, prøv at læse InputStream af HttpUrlConnection instans vil ikke virke. I stedet kan vi forbruge strømmen leveret af HttpUrlConnection.getErrorStream() .

Vi kan bestemme hvilken InputStream at bruge ved at sammenligne HTTP-statuskoden:

int status = con.getResponseCode();

Reader streamReader = null;

if (status > 299) {
    streamReader = new InputStreamReader(con.getErrorStream());
} else {
    streamReader = new InputStreamReader(con.getInputStream());
}

Og endelig kan vi læse streamReader på samme måde som forrige afsnit.

11. Opbygning af det fulde svar

Det er ikke muligt at få den fulde svarrepræsentation ved hjælp af HttpUrlConnection  eksempel.

Men vi kan bygge det ved hjælp af nogle af de metoder, som HttpUrlConnection  instanstilbud :

public class FullResponseBuilder {
    public static String getFullResponse(HttpURLConnection con) throws IOException {
        StringBuilder fullResponseBuilder = new StringBuilder();

        // read status and message

        // read headers

        // read response content

        return fullResponseBuilder.toString();
    }
}

Her læser vi delene af svarene, inklusive statuskoden, statusmeddelelsen og overskrifterne, og tilføjer disse til en StringBuilder eksempel.

Lad os først tilføje svarstatusoplysningerne :

fullResponseBuilder.append(con.getResponseCode())
  .append(" ")
  .append(con.getResponseMessage())
  .append("\n");

Dernæst henter vi overskrifterne ved hjælp af getHeaderFields() og føj hver af dem til vores StringBuilder i formatet HeaderName:HeaderValues :

con.getHeaderFields().entrySet().stream()
  .filter(entry -> entry.getKey() != null)
  .forEach(entry -> {
      fullResponseBuilder.append(entry.getKey()).append(": ");
      List headerValues = entry.getValue();
      Iterator it = headerValues.iterator();
      if (it.hasNext()) {
          fullResponseBuilder.append(it.next());
          while (it.hasNext()) {
              fullResponseBuilder.append(", ").append(it.next());
          }
      }
      fullResponseBuilder.append("\n");
});

Til sidst læser vi svarindholdet som vi gjorde tidligere og tilføje det.

Bemærk, at getFullResponse  metode vil validere, om anmodningen var vellykket eller ej, for at beslutte, om den skal bruge con.getInputStream() eller con.getErrorStream() for at hente anmodningens indhold.

12. Konklusion

I denne artikel viste vi, hvordan vi kan udføre HTTP-anmodninger ved hjælp af HttpUrlConnection klasse.

Den fulde kildekode for eksemplerne kan findes på GitHub.


Java tag