Pertama, penafian sebelumnya: cuplikan kode yang diposting adalah semua contoh dasar. Anda harus menangani hal-hal sepele IOException
dan RuntimeException
seperti itu NullPointerException
, ArrayIndexOutOfBoundsException
dan mendampingi diri Anda sendiri.
Mempersiapkan
Pertama-tama kita perlu tahu setidaknya URL dan rangkaian karakter. Parameter bersifat opsional dan tergantung pada persyaratan fungsional.
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¶m2=%s",
URLEncoder.encode(param1, charset),
URLEncoder.encode(param2, charset));
Parameter kueri harus dalam name=value
format dan disatukan oleh &
. Anda biasanya juga akan menyandi URL parameter kueri dengan menggunakan rangkaian karakter yang ditentukan URLEncoder#encode()
.
The String#format()
hanya untuk kenyamanan. Saya lebih suka ketika saya akan membutuhkan operator penggabungan String +
lebih dari dua kali.
Menembak a permintaan HTTP GET dengan parameter kueri (opsional)
Ini tugas yang sepele. Ini metode permintaan default.
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
Setiap string kueri harus digabungkan ke URL menggunakan ?
. The Accept-Charset
sundulan mungkin petunjuk server apa pengkodean parameter dalam. Jika Anda tidak mengirim string kueri, maka Anda dapat meninggalkan Accept-Charset
sundulan jauh. Jika Anda tidak perlu mengatur header apa pun, maka Anda bahkan dapat menggunakan URL#openStream()
metode pintas.
InputStream response = new URL(url).openStream();
// ...
Either way, jika pihak lain adalah HttpServlet
, maka doGet()
metodenya akan dipanggil dan parameter akan tersedia oleh HttpServletRequest#getParameter()
.
Untuk tujuan pengujian, Anda dapat mencetak isi tanggapan ke stdout seperti di bawah ini:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
Memecat permintaan HTTP POST dengan parameter kueri
Mengatur URLConnection#setDoOutput()
agar true
secara implisit menetapkan metode permintaan ke POST. HTTP POST standar seperti yang dilakukan formulir web adalah jenis di application/x-www-form-urlencoded
mana string kueri ditulis ke badan permintaan.
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();
// ...
Catatan: setiap kali Anda ingin mengirimkan formulir HTML secara terprogram, jangan lupa untuk membawa name=value
pasangan <input type="hidden">
elemen apa pun ke dalam string kueri dan tentu saja juga name=value
pasangan dari<input type="submit">
elemen yang ingin Anda "tekan" secara terprogram (karena yang biasanya digunakan di sisi server untuk membedakan jika tombol ditekan dan jika demikian, yang mana).
Anda juga dapat melemparkan yang diperoleh URLConnection
ke HttpURLConnection
dan menggunakannya HttpURLConnection#setRequestMethod()
. Tapi jika Anda mencoba untuk menggunakan koneksi untuk output Anda masih perlu untuk set URLConnection#setDoOutput()
ke true
.
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
Either way, jika pihak lain adalah HttpServlet
, maka doPost()
metodenya akan dipanggil dan parameter akan tersedia olehHttpServletRequest#getParameter()
.
Sebenarnya mengaktifkan permintaan HTTP
Anda dapat memecat permintaan HTTP secara eksplisit dengan URLConnection#connect()
, tetapi permintaan akan secara otomatis dipecat saat diminta ketika Anda ingin mendapatkan informasi tentang respons HTTP, seperti badan respons yang menggunakan URLConnection#getInputStream()
dan sebagainya. Contoh di atas tidak persis seperti itu, jadi connect()
panggilan itu sebenarnya berlebihan.
Mengumpulkan informasi respons HTTP
Status respons HTTP :
Anda butuh di HttpURLConnection
sini. Keluarkan terlebih dahulu jika perlu.
int status = httpConnection.getResponseCode();
Header respons HTTP :
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
System.out.println(header.getKey() + "=" + header.getValue());
}
Pengodean respons HTTP :
Ketika Content-Type
berisi charset
parameter, maka badan respons kemungkinan berbasis teks dan kami ingin memproses badan respons dengan pengkodean karakter yang ditentukan sisi server.
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.
}
Mempertahankan sesi
Sesi sisi server biasanya didukung oleh cookie. Beberapa formulir web mengharuskan Anda masuk dan / atau dilacak oleh suatu sesi. Anda dapat menggunakan CookieHandler
API untuk mengelola cookie. Anda perlu menyiapkan CookieManager
dengan CookiePolicy
dari ACCEPT_ALL
sebelum mengirim semua permintaan 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();
// ...
Perhatikan bahwa ini diketahui tidak selalu berfungsi dengan baik dalam semua keadaan. Jika gagal untuk Anda, maka yang terbaik adalah mengumpulkan dan mengatur header cookie secara manual. Anda pada dasarnya perlu mengambil semua Set-Cookie
header dari respons login atau GET
permintaan pertama dan kemudian meneruskannya melalui permintaan berikutnya.
// 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]);
}
// ...
The split(";", 2)[0]
apakah ada untuk menyingkirkan atribut cookies yang tidak relevan untuk sisi server seperti expires
, path
, dll Atau, Anda bisa juga menggunakan cookie.substring(0, cookie.indexOf(';'))
bukan split()
.
Mode streaming
Secara HttpURLConnection
default, buffer akan meminta seluruh badan permintaan sebelum mengirimkannya, terlepas dari apakah Anda telah menetapkan sendiri panjang konten yang tetap digunakan connection.setRequestProperty("Content-Length", contentLength);
. Ini dapat menyebabkan OutOfMemoryException
setiap kali Anda secara bersamaan mengirim permintaan POST besar (misalnya mengunggah file). Untuk menghindari ini, Anda ingin mengatur HttpURLConnection#setFixedLengthStreamingMode()
.
httpConnection.setFixedLengthStreamingMode(contentLength);
Tetapi jika panjang konten benar-benar tidak diketahui sebelumnya, maka Anda dapat menggunakan mode streaming chunked dengan mengatur yang HttpURLConnection#setChunkedStreamingMode()
sesuai. Ini akan mengatur Transfer-Encoding
tajuk HTTP chunked
yang akan memaksa badan permintaan dikirim dalam bentuk potongan. Contoh di bawah ini akan mengirim tubuh dalam potongan 1KB.
httpConnection.setChunkedStreamingMode(1024);
Agen pengguna
Itu bisa terjadi bahwa permintaan mengembalikan respons yang tidak terduga, sementara itu berfungsi baik dengan browser web nyata . Sisi server mungkin memblokir permintaan berdasarkan User-Agent
header permintaan. Secara URLConnection
default akan mengaturnya ke Java/1.6.0_19
mana bagian terakhir jelas merupakan versi JRE. Anda dapat menimpa ini sebagai berikut:
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.
Gunakan string User-Agent dari browser terbaru .
Menangani kesalahan
Jika kode respons HTTP adalah 4nn
(Kesalahan Klien) atau 5nn
(Kesalahan Server), maka Anda mungkin ingin membaca HttpURLConnection#getErrorStream()
untuk melihat apakah server telah mengirim informasi kesalahan yang berguna.
InputStream error = ((HttpURLConnection) connection).getErrorStream();
Jika kode respons HTTP -1, maka ada yang salah dengan koneksi dan penanganan respons. The HttpURLConnection
implementasi di JRE yang lebih tua agak buggy dengan menjaga koneksi hidup. Anda mungkin ingin mematikannya dengan menyetel http.keepAlive
properti sistem ke false
. Anda dapat melakukan ini secara terprogram di awal aplikasi Anda dengan:
System.setProperty("http.keepAlive", "false");
Mengunggah file
Anda biasanya menggunakan multipart/form-data
pengodean untuk konten POST campuran (data biner dan karakter). Pengkodean lebih rinci dijelaskan dalam 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();
}
Jika sisi lain adalah a HttpServlet
, maka doPost()
metodenya akan dipanggil dan bagian-bagian akan tersedia oleh HttpServletRequest#getPart()
(perhatikan, maka tidak getParameter()
dan seterusnya!). Namun getPart()
metode ini relatif baru, diperkenalkan di Servlet 3.0 (Glassfish 3, Tomcat 7, dll). Sebelum ke Servlet 3.0, pilihan terbaik Anda menggunakan Apache Commons FileUpload untuk mengurai multipart/form-data
permintaan. Lihat juga jawaban ini untuk contoh pendekatan FileUpload dan Servelt 3.0.
Berurusan dengan situs HTTPS yang tidak terpercaya atau salah konfigurasi
Terkadang Anda perlu menghubungkan URL HTTPS, mungkin karena Anda sedang menulis scraper web. Dalam hal itu, Anda mungkin menghadapi javax.net.ssl.SSLException: Not trusted server certificate
beberapa situs HTTPS yang tidak memperbarui sertifikat SSL mereka, atau a java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
ataujavax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
pada beberapa situs HTTPS yang tidak terkonfigurasi.
Berikut-satu kali menjalankan static
initializer di web kelas scraper Anda harus membuat HttpsURLConnection
lebih ringan untuk orang-orang HTTPS situs dan dengan demikian tidak membuang mereka pengecualian lagi.
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);
}
}
Kata-kata terakhir
The Apache HttpComponents HttpClient adalah jauh lebih nyaman dalam ini semua :)
Parsing dan mengekstraksi HTML
Jika semua yang Anda inginkan adalah parsing dan mengekstraksi data dari HTML, maka lebih baik gunakan parser HTML seperti Jsoup
Ask Question
tombol di kanan atas.--
itu bukan bagian dari batas itu sendiri. Itu hanya string pemisah. Saya telah memutar kembali hasil edit Anda yang tidak valid.HttpClient
sekarang danHttpURLConnection
kejam. android-developers.blogspot.in/2011/09/...Ketika bekerja dengan HTTP, hampir selalu lebih bermanfaat untuk merujuk
HttpURLConnection
daripada kelas dasarURLConnection
(karenaURLConnection
ini adalah kelas abstrak ketika Anda memintaURLConnection.openConnection()
pada URL HTTP itulah yang akan Anda dapatkan kembali).Kemudian Anda dapat daripada mengandalkan
URLConnection#setDoOutput(true)
untuk secara implisit mengatur metode permintaan ke POST daripada melakukanhttpURLConnection.setRequestMethod("POST")
yang beberapa mungkin menemukan lebih alami (dan yang juga memungkinkan Anda untuk menentukan metode permintaan lainnya seperti PUT , DELETE , ...).Ini juga menyediakan konstanta HTTP yang berguna sehingga Anda dapat melakukan:
sumber
setDoOutput()
untuktrue
dinyatakan pengecualian dilemparkan (bahkan jika AndasetRequestMethod("POST")
). Untuk menjadi jelas: pengaturanURLConnection#setDoOutput(true)
untuktrue
secara implisit menetapkan metode permintaan ke POST, tetapi pengaturanhttpURLConnection.setRequestMethod("POST")
untuk POST tidak secara implisit diatursetDoOutput()
ketrue
.Terinspirasi oleh ini dan pertanyaan lain pada SO, saya telah membuat open-source basic-http-client minimal yang mewujudkan sebagian besar teknik yang ditemukan di sini.
google-http-java-client juga merupakan sumber terbuka yang bagus.
sumber
Saya sarankan Anda melihat kode pada kevinsawicki / http-request , pada dasarnya pembungkus di atas
HttpUrlConnection
atasnya menyediakan API yang lebih sederhana jika Anda hanya ingin membuat permintaan sekarang atau Anda dapat melihat sumbernya ( tidak terlalu besar) untuk melihat bagaimana koneksi ditangani.Contoh: Buat
GET
permintaan dengan tipe kontenapplication/json
dan beberapa parameter kueri:sumber
Ada 2 opsi yang dapat Anda gunakan dengan Hits URL HTTP: GET / POST
DAPATKAN Permintaan: -
Permintaan POST: -
sumber
Saya juga sangat terinspirasi oleh respons ini.
Saya sering mengerjakan proyek-proyek di mana saya perlu melakukan beberapa HTTP, dan saya mungkin tidak ingin membawa banyak dependensi pihak ke-3 (yang membawa orang lain dan seterusnya dan seterusnya, dll.)
Saya mulai menulis utilitas saya sendiri berdasarkan pada beberapa percakapan ini (tidak di mana pun dilakukan):
Lalu ada hanya banyak atau metode statis.
Kemudian poskan ...
Baik Anda mendapatkan ide ....
Inilah tes-tesnya:
Anda dapat menemukan sisanya di sini:
https://github.com/RichardHightower/boon
Tujuan saya adalah untuk menyediakan hal-hal umum yang ingin dilakukan dengan cara yang sedikit lebih mudah daripada ....
sumber
doPost
metode ini adacharset
param, yang digunakan untuk mengatur header permintaan, tetapi kemudian data ditulis dengan beberapa charset yang dikodekan kerasIO.CHARSET
. Bug?Memperbarui
Di Java 9, Anda dapat mengirim
GET
permintaan seperti:Kemudian Anda dapat memeriksa yang dikembalikan
HttpResponse
:Karena Klien HTTP baru ini ada di
java.httpclient
jdk.incubator.httpclient
modul, Anda harus mendeklarasikan ketergantungan ini dalammodule-info.java
file Anda :sumber
Awalnya saya disesatkan oleh artikel ini yang nikmat
HttpClient
.Kemudian saya menyadari bahwa saya
HttpURLConnection
akan tinggal dari artikel iniSesuai blog Google :
Setelah membaca artikel ini dan beberapa pertanyaan overflow, saya yakin itu
HttpURLConnection
akan bertahan untuk jangka waktu yang lebih lama.Beberapa pertanyaan SE mendukung
HttpURLConnections
:Di Android, buat permintaan POST dengan URL Data Formulir yang Dienkripsi tanpa menggunakan UrlEncodedFormEntity
HttpPost berfungsi di proyek Java, bukan di Android
sumber
Ada juga OkHttp , yang merupakan klien HTTP yang efisien secara default:
Pertama buat instance dari
OkHttpClient
:Kemudian, siapkan
GET
permintaan Anda :Akhirnya, gunakan
OkHttpClient
untuk mengirim disiapkanRequest
:Untuk detail lebih lanjut, Anda dapat membaca dokumentasi OkHttp
sumber
Anda juga dapat menggunakan
JdkRequest
dari jcabi-http (saya seorang pengembang), yang melakukan semua ini untuk Anda, menghias HttpURLConnection, mem- request permintaan HTTP dan respons parsing, misalnya:Lihat posting blog ini untuk info lebih lanjut: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html
sumber
jika Anda menggunakan http dapatkan tolong hapus baris ini
sumber