sobota, 19 kwietnia 2014

Consuming REST services via Apache HTTP Client - Wprowadzenie do HTTP i REST


1.    Protokół HTTP

HTTP jest protokołem określającym standard przesyłania dokumentów WWW. Wykorzystuje on protokół TCP zazwyczaj wykorzystując port 80.
Standard protokołu HTTP określa norma:
RFC 2616 Hypertext Transfer Protocol -- HTTP/1.1
  • HTTP model komunikacji:
Wielu klientów - jeden serwer
 
Wielu klientów otrzymuje zasób udostępniany przez jeden serwer. Teoretycznie serwis WWW, może być rozproszony na wielu hostach, jednak zawsze na końcu przekierowań mamy jeden adres docelowy.  

  • HTTP szablon komunikacji
 
  • Własności protokołu HTTP
 
Protokół HTTP jest protokołem transmitującym dane tekstowe (zdarzają się również elementy binarne). Każda odpowiedź serwera jest oznaczona odpowiednim kodem. Należy również zaznaczyć, że w protokole HTTP komunikację zawsze inicjuje klient.
  • Miejsce HTTP w modelu ISO/OSI - warstwa aplikacji
 
  • Metody protokołu HTTP -

W zależności od potrzeb protokół HTTP umożliwia nam wykorzystanie kilku metod:

  •    HTTP Request
Każde zapytanie wysłane do serwera musi posiadać odpowiednią strukturę.

a)      Typ metody żądania i jej parametry
b)      Nagłówek żądania (nazwa hosta docelowego, typ i długość przesyłanych danych (POST) , typ przeglądarki, ciasteczka, poprzednia strona)
c)      Pusta linia
d)      Treść danych przesyłanych do serwera (opcjonalnie)

GET /path/file.html HTTP/1.0
From: someuser@jmarshall.com
User-Agent: HTTPTool/1.0
[blank line here]
  • HTTP Response
Struktura odpowiedzi serwera jest następująca:

a)      Wersja protokołu, kod błędu, opis kodu

b)      Nagłówek odpowiedzi (czas serwera, informacje o serwerze, ciasteczka, informacje o typie zasobu i jego długości)

c)      Pusta linia
            d)    Treść danych przesyłanych przez serwer
HTTP/1.0 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/html
Content-Length: 1354

<html>
<body>
<h1></h1>
(more file contents)
  .
  .
  .
</body>
</html>
  • Najważniejsze metody HTTP – POST i GET 
Metoda POST:
- wysyła dane do zasobu url do dalszego przetwarzania. Najczęściej do formularzy
- dane przesyłane w treści żądania
- służy do wysyłania nowych bądź aktualizacji bieżących zasobów

Metode GET:
- pobiera z serwera zasób opisany poprzez URL
  • Kody błędów

Każdy programista powinien znać zakres kodów błędów w komunikacji serwer – klient.





2.    REST

REST – Representional State Transfer jest architekturą projektowania sieciowych aplikacji. Polega on na użyciu komunikacji stateless – która traktuje każdy request jako osobną transakcje. Używa on komunikacji typu klient- serwer. REST komunikuje się protokołem HTTP.

REST jest alternatywą dla innych ciężkich mechanizmów przesyłania danych poprzez sieć( CORBA,RPC,SOAP). Umożliwia wykonywanie wszystkich operacji CRUD.
Należy zauważyć, że REST nie jest standardem.

3.    Sniffing HTTP requests/response


Sniffer Wireshark umożliwia nam podglądnięcie struktury żądania/odpowiedzi poprzez protokół HTTP. Aby to ułatwić, możemy skrozystać z odpowiednich filtrów. 
Uruchamiamy program Wireshark i w opcji filtra aby pokazać requesty:

 
Wpisujemy: 


http.request.method == GET or http.request.method == POST
 
Aby odfiltrować odpowiedzi:
http.response

Znając RC możemy też użyć

http.response.code=kod

Odpowiednie wyniki metody GET do www.wp.pl  są następujące:
a) request

 

b) response

 

4.    Struktura bibliotek Apache HTTPComponents


Apache HTTP Client jest częścią projektu Apache HttpComponents. Jest on odpowiedzialny za tworzenie I utrzymanie niskopoziomowego API Javy stworzonego dla obsługi protokołów HTTP oraz protokołów z nim powiązanych.
W chwili obecnej najnowszym GA jest build 4.3.3.

Projekt Apache HTTPComponents składa się z kilku części:

4.1.      HttpComponents Core

Zawiera zestaw niskopoziomowych bibliotek, do budowy zarówno serwera jak I klienta usług HTTP .  HttpCore wspiera 2 modele budowy aplikacji typu I/O w języku Java
1.1.   Blokujący model I/O bazujący na standardowych bibliotekach I/O
1.2.   Nieblokujący model I/O sterowany zdarzeniami bazujący na java NIO

Do budowy aplikacji z intensywnymi, mało opóźniającymi scenariuszami wymiany danych zaleca się pierwszy z modeli, natomiast z drugiego z modeli korzystamy gdy zależy nam bardziej na możliwości otrzymania dużej ilości połączeń w efektywny sposób

4.2.      HttpComponents Client

Jest to implementacja agenta protokołu HTTP/1.1 bazująca na HTTPCore. Dostarcza komponentów umożliwających autentykację, śledzenie stanu oraz zarządzanie połęczeniem poprzez protokół HTTP.

4.3.      HttpComponents AsyncClient


Jest to implementacja agenta protokołu HTTP/1.1 bazująca na bibliotekach HttpCore NIO oraz HttpCore.  Komponent ten, używamy gdy musimy odebrać dużą liczbę połączeń, stawiając na drugim miejscu perfrormance

4.4.      Commons HttpClient

Moduł ten stał się ostatnio deprecated. Użytkownikom Commons HttpClient zaleca się migrację do HttpComponents Client

5.    Biblioteki oraz dokumentacja Apache HTTP Client

Wszystkie biblioteki Apache HTTP Client możemy pobrać korzystając ze strony:
Możliwe jest również dodanie dependencji w pliku POM.

Na stronie: https://hc.apache.org/ znajdziemy również bogaty zestaw tutoriali oraz dokumentację.


Pora zatem przejść do pracy i przesłać nasz pierwszy request.

6.    Aplikacja

Po stworzeniu projektu Mavena, bez wyboru archetypu, możemy dodać dependencję do bibliotek Apache HttpClient. W tym celu w pliku POM.xml dodajemy:


<dependency> 
 <groupId>org.apache.httpcomponents</groupId>
 <artifactId>httpClient</artifactId>>
 <version>4.3.3</version>
</dependency> 


Następnie możemy napisać klasę realizującą wywołanie metody HTTPGet dla www.wp.pl

package com.justdiscoverit.blogstpot;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class TestApacheHttpClient {

    public static void main(String... strings) {
        // CloseableHttpClient - klasa bezpieczna watkowo
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://www.wp.pl");
        CloseableHttpResponse response1 = null;
        try {
            response1 = httpclient.execute(httpGet);

            // polaczenie HTTP jest utrzymywane przes obiekt odnoszacy sie
            // do referencji response1. Aby zamknac poprawnie polaczenie
            // i zwolnic zasoby nalezy wywolac metode consume z klasy
            // EntityUtils lub przerwac wykonywanie metoda close

            // czytamy kod odpowiedzi serwera
            System.out.println(response1.getStatusLine());
            HttpEntity entity1 = response1.getEntity();

            // czytamy content odpowiedzi HttpGet linia po linii
            BufferedReader rd = new BufferedReader(new InputStreamReader(
                    entity1.getContent()));
            String line = "";
            StringBuffer sb = new StringBuffer();
            while ((line = rd.readLine()) != null) {
                sb.append(line + "\n");
            }

            System.out.println(sb);

            // zamykamy polaczenie
            EntityUtils.consume(entity1);
        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                response1.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
} 
 
Po wykonaniu powyższego programu dostajemy output na consoli:

HTTP/1.1 200 OK
<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="utf-8">
    <title>Wirtualna Polska - www.wp.pl</title>
    <meta name="Expires" content="0">
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="X-XRDS-Location" content="http://serwer.openid.wp.pl/?xrds=1">
    <meta name="author" content="Wirtualna Polska">
    <meta name="keywords" content="wp.pl,wp,Wirtualna Polska,Wirtualna,Polska,Katalog,Katalog WWW,Firmy,Encyklopedia,Pogoda,Wiadomosci,Program,Telewizja,Sklep,Kawiarenka,MP3">
    <meta name="description" content="Pierwszy horyzontalny portal internetowy w Polsce. Skuteczne medium reklamowe. Bogactwo serwisow informacyjnych i finansowych. Centrum wyszukiwania, komunikacji i rozrywki: wiadomosci, wyszukiwarki, poczta, webpark, czat, komunikator, SMS, randki, kartki, krzyĹĽĂłwki, mp3, gry, gry on-line, muzyka, film. Platforma e-commerce: aukcje, zakupy, przetargi, oferty, turystyka.">
    <meta name="robots" content="index,follow">
    <meta property="og:image" content="http://x.wpimg.pl/i/ivar/layout/201201/logo_wppl_1200x630.png">
    <meta http-equiv="X-UA-Compatible" content="IE=10">
.....

Teraz omówimy poszczególne fragmenty kodu:
CloseableHttpClient httpclient = HttpClients.createDefault();
Klasa CloseableHttpClient jest  klasą implementującą interfejsy Closeable, AutoCloseable oraz HTTPClient.Implementacja 2 pierwszych interfejsów sprawia, że klasa ta jest uważana za klasę reprezentującą zasoby zewnętrzne. Oznacza to, że zasoby powinny być zwalniane metodą close(). Różnica pomiędzy intefejsami AutoCloseable i Closeable jest taka, że metoda close() intefejsu Closeable może wyrzucać jedynie wyjątek typu IOException natomiast metoda close() interfejsu AutoCloseable może wyrzucać wyjątek dowolnego typu. Interfejs Closeable stanowi rozszerzenie interfejsu AutoCloseable. Klasa HttpClients jest specjalną klasą posiadającą prywatny konstruktor. Posiada ona kilka statystycznych metod umożliwiających stworzenie obiektu typu CloseableHttpClient z predefiniowanymi ustawieniami.
CloseableHttpResponse response1 = null;
CloseableHttpResponse jest intefejsem implementującym również interfejsy AutoCloseable, Closeable jak również interfejsy HttpMessage, HttpResponse.  
response1 = httpclient.execute(httpGet);
Metoda execute klasy CloseableHttpClient wykonuje zapytanie, oraz zwraca referencję do obiektu implementującego interfejs CloseableHttpResponse.
 System.out.println(response1.getStatusLine());
Za pomocą metody getStatusLine() możemy otrzymać RC oraz opis kodu, np:HTTP/1.1 200 OK
HttpEntity entity1 = response1.getEntity();
 Metoda getEntity() zwraca obiekt HttpEntity będący abstrakcyjną reprezentacją żądań bądź odpowiedzi. Składa się z nagłowka oraz opcjonalnie z ciała.
 BufferedReader rd = new BufferedReader(new InputStreamReader(
                    entity1.getContent()));
Za pomocą metody getContent() otrzymujemy obiekt klasy InputStream, który następnie wykorzystujemy do przeczytania odpowiedzi serwera. 
 EntityUtils.consume(entity1);
 Aby zwonić zasoby należy użyć metody statycznej consume klasy EntityUtils. W klauzuli finally zawarte jest jeszcze wywołanie 
response1.close();
Dzięki niemu możemy mieć pewność, że nawet podczas wystąpienia wyjątku zasoby zostaną zwolnione.  

W kolejnej części  pokażę zastosowanie Apache HTTPClient w kooperacji z Google Calendar.

Źródła:
http://tjaworski.kis.p.lodz.pl/zajecia/ps2/HTTP.pdf
https://hc.apache.org/httpcomponents-client-4.3.x/httpclient/apidocs/
http://www.jmarshall.com/easy/http/#sample




1 komentarz:

  1. Napisałeś że w protokole http to klient zawsze inicjalizuje połączenie, więc jak to wygląda w technologii push serwer?

    OdpowiedzUsuń