嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2015-12-03 1694 次浏览 标签 : Java

免费领取阿里云优惠券 我的直播 - 《PHP 进阶之路》

先说说几个概念关键字HttpURLConnection,HttpClientCloseableHttpClient


在 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;
}


嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

[视频直播] PHP 进阶之路 - 亿级 pv 网站架构的技术细节与套路 直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

评论列表