美文网首页
使用 HTTP 协议访问网络

使用 HTTP 协议访问网络

作者: TTTqiu | 来源:发表于2016-05-09 14:38 被阅读224次

    参考可见:
    Android网络请求心路历程
    浅谈Android中Http请求与缓存(上)

    在 Android 6.0 (API 23) 中,Google 已经移除了 Apache HttpClient 相关的类。推荐使用 HttpUrlConnection。


    一、简单使用 HttpURLConnection


    1. 获取 HttpURLConnection 的实例。
    • new 出一个** URL 对象**,并传入目标的网络地址:
    URL url = new URL("http://www.baidu.com");
    
    • 再调用 **openConnection() **方法获得:
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    
    2. 设置 HTTP 请求所使用的方法。
    • GET 表示希望从服务器那里获取数据
    • POST 表示希望提交数据给服务器。
    connection.setRequestMethod("GET");
    connection.setRequestMethod("POST");
    
    3. 进行一些设置,如设置连接超时、读取超时的毫秒数等。
    connection.setConnectTimeout(8000);
    connection.setReadTimeout(8000);
    
    4. 调用** getInputStream()** 方法获取到服务器返回的输入流。
    InputStream in = connection.getInputStream();
    
    5. 最后调用 **disconnect() **方法将这个 HTTP 连接关闭掉。
    connection.disconnect();
    

    接受数据示例:

    public class MainActivity extends Activity implements OnClickListener {
        public static final int SHOW_RESPONSE = 0;
        private Button sendRequest;
        private TextView responseText;
        private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW_RESPONSE:
                    String response = (String) msg.obj;
                    // 在这里进行UI操作,将结果显示到界面上
                    responseText.setText(response);
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            sendRequest = (Button) findViewById(R.id.send_request);
            responseText = (TextView) findViewById(R.id.response_text);
            sendRequest.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            if (v.getId() == R.id.send_request) {
                sendRequestWithHttpURLConnection();
            }
        }
    
        private void sendRequestWithHttpURLConnection() {
            // 开启线程来发起网络请求
            new Thread(new Runnable() {
                @Override
                public void run() {
                    HttpURLConnection connection = null;
                    try {
                        URL url = new URL("http://www.baidu.com");
                        connection = (HttpURLConnection) url.openConnection();
                        connection.setRequestMethod("GET");
                        // 设置可以从服务器读数据,默认为 true 可不设
                        connection.setDoInput(true);
                        connection.setConnectTimeout(8000);
                        connection.setReadTimeout(8000);
                        if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){
                            InputStream in = connection.getInputStream();
                            // 下面对获取到的输入流进行读取
                            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                            StringBuilder response = new StringBuilder();
                            String line;
                            while ((line = reader.readLine()) != null) {
                                response.append(line);
                            }
                            in.close();
                            Message message = new Message();
                            message.what = SHOW_RESPONSE;
                            // 将服务器返回的结果存放到Message中
                            message.obj = response.toString();
                            handler.sendMessage(message);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        if (connection != null) {
                            connection.disconnect();
                        }
                    }
                }
            }).start();
        }
    }
    
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.networktest"
        android:versionCode="1"
        android:versionName="1.0" >
        ......
        <uses-permission android:name="android.permission.INTERNET" />
        ......
    </manifest>
    

    提交数据示例:

    connection.setRequestMethod("POST");
    DataOutputStream out = new DataOutputStream(connection.getOutputStream());
    out.writeBytes("username=admin&password=123456");
    

    二、进阶


    1. 以字符数组获取响应数据

    以上是通过 inputSream 来获取响应数据,但 inputSream 用过后就不能使用了(?),有时为了以后再使用响应数据,或某些更方便的情况下,可以用字符数组的方式来获取响应数据。

            ......
            InputStream inputStream = connection.getInputStream()
            byte[] buffer = new byte[1024];
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int length;
            try {
                // .read(byte[]) 一次读传入缓存区大小,返回读到的字节数,没读到返回 -1
                while ((length = inputStream.read(buffer)) != -1) {
                    // byteArrayOutputStream 扩展 length 大小的容量,并写入 buffer 内容
                    byteArrayOutputStream.write(buffer, 0, length);
                }
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // 记得关闭
                byteArrayOutputStream .close();
            }
    

    转为 String:

    String result=byteArrayOutputStream.toString();
    

    转为 Bitmap:

    Bitmap result=BitmapFactory.decodeByteArray(byteArrayOutputStream.toByteArray(),0,byteArrayOutputStream.size());
    

    2. GET 提交参数

    GET 方法也可以提交参数,不过不是像 POST 方法把参数放在请求体里,而是在** url 后面加上参数**,形式为XXXXXXXX?param1=value1&param2=value2。如:
    http://www.jianshu.com?username=TTT&password=123456

    3. POST 提交

    POST 提交是编码放在请求体里。

    (1)提交参数

    (这种键值对参数一般用 application/x-www-form-urlencoded 编码方式最方便,当然也可以用 multipart/form-data编码方式,见下文。)

    如:

      POST /meme.php/home/user/login HTTP/1.1 
      Host: 114.215.86.90 
      Cache-Control: no-cache 
      Postman-Token: bd243d6b-da03-902f-0a2c-8e9377f6f6ed 
      Content-Type: application/x-www-form-urlencoded 
    
      tel=13637829200&password=123456
    
    • 要在 header 中设置编码方式 Content-Type: application/x-www-form-urlencoded
      connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    • 例子,把 Map 中的所有参数组装成 body:
        /**
         * 获得body参数字节数组
         */
        public byte[] getBody() {
            StringBuilder bodyString = new StringBuilder();
            byte[] body = null;
            if (params != null && params.size() > 0) {
                try {
                    // 把参数拼接为"name=TTT&password=123456"形式的字符串
                    for (Map.Entry<String, String> entry : params.entrySet()) {
                        bodyString.append(URLEncoder.encode(entry.getKey(), "UTF-8"))
                                .append("=")
                                .append(URLEncoder.encode(entry.getValue(), "UTF-8"))
                                .append("&");
                    }
                    // 去掉最后一个“&”
                    bodyString.deleteCharAt(bodyString.length() - 1);
                    body = bodyString.toString().getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
            return body;
        }
    
    • 最后在网络请求中把 body 写入 outputStream。注意要设置可以向服务器写数据:
                    // 设置可以向服务器写数据,默认为 false
                    connection.setDoOutput(true);
                    ......
                    outputStream = connection.getOutputStream();
                    outputStream.write(body);
    
    (2)上传文件

    参考可见:
    浅谈Android中Http请求与缓存(上)
    Android基于Http协议实现文件上传功能的方法

    如:

    POST http://58.252.100.248/4.0/blkupload HTTP/1.1
    Content-Length: 131950
    Content-Type: multipart/form-data; boundary=--------UpsClient.Package
    Host: 58.252.100.248
    Connection: Keep-Alive
    User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
    // 空行
    ----------UpsClient.Package
    Content-Disposition: form-data; name="filehash"
    // 空行
    62661949192F70AA0EE2F21DF99D34B8837E14FD
    ----------UpsClient.Package
    Content-Disposition: form-data; name="bigblkoffset"
    // 空行
    0
    ----------UpsClient.Package
    Content-Disposition: form-data; name="uploadfile"; filename="file.txt"
    Content-Type: application/octet-stream
    // 空行
    (file.txt 文件的内容)
    ----------UpsClient.Package--
    // 空行
    
    • 要在 header 中设置编码方式 Content-Type: multipart/form-data; boundary=--------UpsClient.Package
      connection.setRequestProperty("Content-Type", "multipart/form-data")+" ;boundary="+边界标识(String 类型));
    • 边界标识:用来分隔每条数据。可以用UUID.randomUUID().toString();随机生成,也可以自己设定。
      具体使用:--+边界标识+\r\n(换行)
      最后一个要在末尾再加一个--表示结束:--+边界标识+--+\r\n(换行)
    • 对于string类型,只需要 content-disposition 和 name 属性即可。name 是服务器端需要的 key,如 username、password。
      对于文件上传,还需要指定 filename 和 content-type 属性。
    • 注意,例子中的几处空行都不能少。

    相关文章

      网友评论

          本文标题:使用 HTTP 协议访问网络

          本文链接:https://www.haomeiwen.com/subject/ypcsrttx.html