String message = URLEncoder.encode("my message", "UTF-8");
try {
// instantiate the URL object with the target URL of the resource to
// request
URL url = new URL("http://www.example.com/comment");
// instantiate the HttpURLConnection with the URL object - A new
// connection is opened every time by calling the openConnection
// method of the protocol handler for this URL.
// 1. This is the point where the connection is opened.
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// set connection output to true
connection.setDoOutput(true);
// instead of a GET, we're going to send using method="POST"
connection.setRequestMethod("POST");
// instantiate OutputStreamWriter using the output stream, returned
// from getOutputStream, that writes to this connection.
// 2. This is the point where you'll know if the connection was
// successfully established. If an I/O error occurs while creating
// the output stream, you'll see an IOException.
OutputStreamWriter writer = new OutputStreamWriter(
connection.getOutputStream());
// write data to the connection. This is data that you are sending
// to the server
// 3. No. Sending the data is conducted here. We established the
// connection with getOutputStream
writer.write("message=" + message);
// Closes this output stream and releases any system resources
// associated with this stream. At this point, we've sent all the
// data. Only the outputStream is closed at this point, not the
// actual connection
writer.close();
// if there is a response code AND that response code is 200 OK, do
// stuff in the first if block
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// OK
// otherwise, if any other status code is returned, or no status
// code is returned, do stuff in the else block
} else {
// Server returned HTTP error code.
}
} catch (MalformedURLException e) {
// ...
} catch (IOException e) {
// ...
}
Pierwsze 3 odpowiedzi na Twoje pytania są wymienione jako komentarze w tekście obok każdej metody w powyższym przykładzie HTTP POST.
Z getOutputStream :
Zwraca strumień wyjściowy, który zapisuje w tym połączeniu.
Zasadniczo myślę, że dobrze rozumiesz, jak to działa, więc pozwolę sobie powtórzyć w kategoriach laika. getOutputStream
w zasadzie otwiera strumień połączenia z zamiarem zapisania danych na serwerze. W powyższym przykładzie "wiadomość" może być komentarzem, który wysyłamy do serwera, który reprezentuje komentarz pozostawiony w poście. Kiedy widzisz getOutputStream
, otwierasz strumień połączenia do zapisu, ale tak naprawdę nie zapisujesz żadnych danych, dopóki nie zadzwonisz writer.write("message=" + message);
.
Z getInputStream () :
Zwraca strumień wejściowy, który odczytuje z tego otwartego połączenia. SocketTimeoutException może zostać zgłoszony podczas odczytu ze zwróconego strumienia wejściowego, jeśli limit czasu odczytu wygaśnie, zanim dane będą dostępne do odczytu.
getInputStream
robi odwrotnie. Podobnie getOutputStream
, otwiera również strumień połączenia , ale jego celem jest odczyt danych z serwera, a nie zapisywanie do niego. Jeśli połączenie lub otwarcie strumienia nie powiedzie się, zobaczysz plik SocketTimeoutException
.
A co z getInputStream? Ponieważ jestem w stanie uzyskać odpowiedź tylko w getInputStream, czy to oznacza, że nie wysłałem jeszcze żadnego żądania do getOutputStream, ale po prostu nawiązałem połączenie?
Pamiętaj, że wysłanie żądania i wysłanie danych to dwie różne operacje. Kiedy wywołujesz getOutputStream lub getInputStream url.openConnection()
, wysyłasz żądanie do serwera w celu ustanowienia połączenia. Występuje uzgadnianie, które ma miejsce, gdy serwer odsyła potwierdzenie, że połączenie zostało nawiązane. W tym momencie jesteś przygotowany do wysyłania lub odbierania danych. Dlatego nie musisz wywoływać funkcji getOutputStream, aby ustanowić połączenie i otworzyć strumień, chyba że celem żądania jest wysłanie danych.
Mówiąc prościej, złożenie getInputStream
prośby jest równoznaczne z wykonaniem telefonu do domu przyjaciela, aby powiedzieć: „Hej, czy jest w porządku, jeśli przyjdę i pożyczę tę parę uchwytów imadła?”. a twój przyjaciel ustanawia uścisk dłoni mówiąc: „Jasne! Chodź i weź to”. Następnie, w tym momencie, zostaje nawiązane połączenie, idziesz do domu przyjaciela, pukasz do drzwi, prosisz o uchwyty imadła i wracasz do domu.
Skorzystanie z podobnego przykładu dla getOutputStream
obejmowałoby zadzwonienie do znajomego i powiedzenie: „Hej, mam pieniądze, które jestem ci winien, czy mogę ci je wysłać”? Twój przyjaciel, potrzebujący pieniędzy i chory w środku, że trzymałeś je tak długo, mówi: „Jasne, daj spokój tani draniu”. Więc idziesz do domu swojego przyjaciela i "PRZEŚLIJ" mu pieniądze. Potem cię wyrzuca i wracasz do domu.
Kontynuując przykład laika, spójrzmy na niektóre Wyjątki. Jeśli zadzwoniłeś do znajomego i nie było go w domu, może to oznaczać błąd 500. Jeśli zadzwoniłeś i otrzymałeś wiadomość o rozłączonym numerze, ponieważ twój znajomy jest zmęczony ciągłym pożyczaniem pieniędzy, oznacza to, że nie znaleziono strony 404. Jeśli telefon nie działa, ponieważ nie zapłaciłeś rachunku, może to być wyjątek IOException. (UWAGA: ta sekcja może nie być w 100% poprawna. Ma na celu dać ogólne pojęcie o tym, co się dzieje w kategoriach laika).
Pytanie nr 5:
Tak, masz rację, że openConnection po prostu tworzy nowy obiekt połączenia, ale go nie ustanawia. Połączenie jest nawiązywane w momencie wywołania metody getInputStream lub getOutputStream.
openConnection
tworzy nowy obiekt połączenia. Z adresu URL.openConnection javadocs :
Nowe połączenie jest otwierane za każdym razem przez wywołanie metody openConnection programu obsługi protokołu dla tego adresu URL.
Połączenie jest ustanawiane, gdy wywołujesz openConnection, a InputStream, OutputStream lub oba są wywoływane podczas ich tworzenia.
Pytanie nr 6 :
Aby zmierzyć narzut, zwykle zawijam bardzo prosty kod czasowy wokół całego bloku połączeń, na przykład:
long start = System.currentTimeMillis();
log.info("Time so far = " + new Long(System.currentTimeMillis() - start) );
// run the above example code here
log.info("Total time to send/receive data = " + new Long(System.currentTimeMillis() - start) );
Jestem pewien, że istnieją bardziej zaawansowane metody pomiaru czasu żądania i narzutu, ale ogólnie jest to wystarczające dla moich potrzeb.
Aby uzyskać informacje na temat zamykania połączeń, o które nie pytałeś, zobacz Kiedy w Javie zamyka się połączenie URL? .
Returns an output stream that writes to this connection.
iReturns an input stream that reads from this open connection.
. Strumień wyjściowy i wejściowy są oddzielone od połączenia.Tim Bray przedstawił zwięzły krok po kroku, stwierdzając, że openConnection () nie ustanawia rzeczywistego połączenia. Zamiast tego, rzeczywiste połączenie HTTP nie jest ustanawiane, dopóki nie wywołasz metod takich jak getInputStream () lub getOutputStream ().
http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection
źródło
Na porcie określonym w adresie URL, jeśli istnieje, w przeciwnym razie 80 dla protokołu HTTP i 443 dla protokołu HTTPS. Uważam, że jest to udokumentowane.
Gdy wywołujesz metodę getInputStream (), getOutputStream () lub getResponseCode () bez uzyskania wyjątku.
Nie i nic.
Każde z nich najpierw łączy się, jeśli to konieczne, a następnie zwraca wymagany strumień.
Patrz wyżej.
Tak.
Połącz: nie spiesz się, aby funkcja getInoutStream () lub getOutputStream () została zwrócona, w zależności od tego, które wywołanie jest pierwsze. Czytaj: czas od rozpoczęcia pierwszego czytania do uzyskania EOS.
źródło
W którym momencie protokół HTTPURLConnection próbuje nawiązać połączenie z podanym adresem URL?
Warto wyjaśnić, istnieje instancja „UrlConnection”, a następnie podstawowe połączenie gniazda Tcp / Ip / SSL , 2 różne koncepcje. Instancja „UrlConnection” lub „HttpUrlConnection” jest synonimem pojedynczego żądania strony HTTP i jest tworzona podczas wywoływania url.openConnection (). Ale jeśli zrobisz wiele adresów url.openConnection () z jednej instancji 'url', to jeśli będziesz mieć szczęście, ponownie użyją tego samego gniazda Tcp / Ip i uzgadniania SSL ... co jest dobre, jeśli jesteś wykonywanie wielu żądań stron do tego samego serwera, szczególnie przydatne, jeśli używasz SSL, gdzie narzut związany z ustanowieniem gniazda jest bardzo wysoki.
Zobacz: implementacja HttpURLConnection
źródło
Wykonałem ćwiczenie, aby przechwycić wymianę pakietów na niskim poziomie i stwierdziłem, że połączenie sieciowe jest wyzwalane tylko przez operacje takie jak getInputStream, getOutputStream, getResponseCode, getResponseMessage itp.
Oto wymiana pakietów przechwycona, gdy próbuję napisać mały program do przesłania pliku do Dropbox.
Poniżej znajduje się mój program zabawek i adnotacja
źródło