先说说几个概念关键字HttpURLConnection
,HttpClient
,CloseableHttpClient
。
在 JDK 的 java.net 包中已经提供了访问 HTTP 协议的基本功能:HttpURLConnection。但是对于大部分应用程序来说,JDK 库本身提供的功能还不够丰富和灵活。 HttpURLConnection是java的标准类,什么都没封装,用起来太原始,不方便,比如重访问的自定义,以及一些高级功能等。
HttpClient是个很不错的开源框架,封装了访问http的请求头,参数,内容体,响应等等, HttpClient模块用来提供高效的、最新的、功能丰富的支持 HTTP 协议工具包,并且它支持 HTTP 协议最新的版本和建议。使用HttpClient可以快速开发出功能强大的Http程序。
HttpClient就是一个增强版的HttpURLConnection,HttpURLConnection可以做的事情HttpClient全部可以做;HttpURLConnection没有提供的有些功能,HttpClient也提供了,但它只是关注于如何发送请求、接收响应,以及管理HTTP连接。
最后org.apache.http.impl.client.CloseableHttpClient
它是一个抽象类,它实现了org.apahce.http.client.HttpClient
接口。
一、HttpClient HttpPost
使用 httpclient 传递键值对
需要导入的包有
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.3.5</version> </dependency>
public static String post(String url,List<NameValuePair> params) throws Exception{ CloseableHttpClient httpclient = HttpClients.createDefault(); String responseText = ""; CloseableHttpResponse httpResponse = null; try { HttpPost httppost = new HttpPost(url); httppost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); httpResponse = httpclient.execute(httppost); if(httpResponse.getStatusLine().getStatusCode()==200){ responseText = EntityUtils.toString(httpResponse.getEntity()); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (httpResponse != null){ httpResponse.close(); } } catch (Exception e) { e.printStackTrace(); } } return responseText; }
使用样例
String url = "http://yunpian.com/v1/sms/send.json"; List<NameValuePair> nameValuePairs = new ArrayList<>(); nameValuePairs.add(new BasicNameValuePair("apikey","xxx")); nameValuePairs.add(new BasicNameValuePair("mobile",tel)); nameValuePairs.add(new BasicNameValuePair("text", text)); String response = HttpRequest.post(url, nameValuePairs);
直接传入二进制实体
//byte[] data httpPost.setEntity(new ByteArrayEntity(data, ContentType.APPLICATION_FORM_URLENCODED));
二、URLConnection 直接传入 post 实体内容的方式
public static String sendPost(String url, String content) { OutputStreamWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new OutputStreamWriter(conn.getOutputStream()); out.write(content); out.flush(); out.close(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { if(result.lenght() > 0){ result += "\n" + line; } result += line; } } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; }
如果服务器端用 php 来接收
echo file_get_contents("php://input"); echo "\n"; var_export($_POST);
发送这样的两个请求
System.out.println(sendPost("http://localhost/3.php","a=1&b=2")); System.out.println(sendPost("http://localhost/3.php","123"));
结果如下
a=1&b=2 array ( 'a' => '1', 'b' => '2', ) 123 array ( )
第二种方式用$_POST
方式是接收不到的,这也是与第一种以键值对的形式发送的区别。
三、从文件读取数据 POST
主要是FileInputStream
的使用,对得到的数据content
是采用键值对的形式还是直接放入 http 实体,取决于服务器的接收方式了。
//文件的读取 String content = ""; try { FileInputStream fileInputStream = new FileInputStream(new File("./test.log")); byte[] b = new byte[fileInputStream.available()]; fileInputStream.read(b); fileInputStream.close(); content = new String(b,"UTF-8"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
顺便记录下文件的写入
//文件的写入 try { FileOutputStream fileOutputStream = new FileOutputStream(new File("./test.log")); fileOutputStream.write(content.getBytes()); fileOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
四、二进制安全流方式的 POST
三方法中把byte
转成String
的时候,不传如字符编码,也会默认带有编码。实际测试发现在把byte
转成String
编码时,是不安全的,数据会被篡改。
OutputStream
默认是支持write byte[]
的。
public void write(byte b[]) throws IOException { write(b, 0, b.length); }
public static String post(String url, byte[] content) { OutputStream out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); URLConnection conn = realUrl.openConnection(); conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setDoOutput(true); conn.setDoInput(true); out = conn.getOutputStream(); out.write(content); out.flush(); out.close(); in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { if (result.length() > 0){ result += "\n" + line; } result += line; } } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; }
直接从文件读取二进制数据
public static String post(String url, File file) { FileInputStream stream = null; try { stream = new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); return null; } DataOutputStream out = null; BufferedReader in = null; String result = ""; byte b[] = new byte[1024]; try { URL realUrl = new URL(url); URLConnection conn = realUrl.openConnection(); conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setDoOutput(true); conn.setDoInput(true); out = new DataOutputStream(conn.getOutputStream()); int len = 0; while ((len = stream.read(b)) != -1){ out.write(b, 0, len); } stream.close(); out.flush(); out.close(); in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { if (result.length() > 0){ result += "\n" + line; } result += line; } } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (Exception ex) { ex.printStackTrace(); } } return result; }