Android HTTP request method: HttpURLConnection


Introduction to this section:

In the previous two sections we learned some conceptual things, the HTTP protocol and some things in the protocol header, but in this section we It’s time to pile up the code, and this section is about one of the Http request methods provided by Android: HttpURLConnection. In addition to this, there is another kind of HttpClient, which we will talk about in the next section! However, once the request becomes complicated, the former can be used It is very troublesome, and the latter is often used by us in Java packet capture. It is from Apache. After all, it is not Google’s own son, but in version 4.4 HttpURLConnection has been replaced by OkHttp! Well, keeping pace with the times, I decided to talk about this after talking about HttpClient. OkHttp! By the way, generally we don’t use HttpURLConnection and HttpClient in actual development, but use others to encapsulate them. Good third-party network request frameworks, such as: Volley, android-async-http, loopj, etc., because network operations involve Asynchronous and multi-threading are very troublesome if you do it yourself, so for actual development, you should directly use a third party! ! Of course, I’ll also study It doesn’t matter, after all, the third party is also built on these foundations, with a high-quality architecture and various optimizations! Okay, without further ado, let’s get started Contents of this section!


1. Introduction to HttpURLConnection

Answer: A multi-purpose, lightweight HTTP client that can be used to perform HTTP operations. most applications. Although the API provided by HttpURLConnection is relatively simple, it also makes it easier for us to use Use and extend it. Inherits to URLConnection, an abstract class, and cannot directly instantiate objects. By calling openCollection() Method to obtain the object instance, the default is with gzip compression;


2. Steps to use HttpURLConnection

The steps to use HttpURLConnection are as follows:

  • Create a URL object: URL url = new URL(http://www.baidu.com);
  • Call openConnection() of the URL object To get the HttpURLConnection object instance: HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  • Set the method used for HTTP requests: GET or POST, or other request methods such as: PUTconn.setRequestMethod("GET");
  • Set the connection timeout, the number of milliseconds for the read timeout, and some message headers that the server hopes to getconn.setConnectTimeout(6*1000); conn.setReadTimeout(6 * 1000);
  • Call the getInputStream() method to obtain the input stream returned by the server, and then read the input stream InputStream in = conn .getInputStream();
  • Finally call the disconnect() method to close the HTTP connectionconn.disconnect();

PS: In addition to the above, sometimes we may also need to judge the response code, such as 200: if(conn.getResponseCode() != 200) and then some processing. Also, maybe sometimes we There is no need to pass any parameters, but to directly access a page, we can directly use: final InputStream in = new URL("url").openStream(); Then read the stream directly, but this method is suitable for direct access to the page. The underlying implementation is actually return openConnection().getInputStream(), and we can't yet set some It’s just a request, so you have to weigh it yourself whether you want to write it like this!


3.HttpURLConnection usage examples

Here we mainly write two different usage examples for GET and POST requests. We can conn.getInputStream() What is obtained is a stream, so we need to write a class to convert the stream into a binary array! The tool class is as follows:

StreamTool.java:

/**
 * Created by Jay on 2015/9/7 0007.
 */
public class StreamTool {
    //从流中读取数据
    public static byte[] read(InputStream inStream) throws Exception{
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while((len = inStream.read(buffer)) != -1)
        {
            outStream.write(buffer,0,len);
        }
        inStream.close();
        return outStream.toByteArray();
    }
}

Now we can start playing with our examples!


1) HttpURLConnection sends GET request code example

Running renderings:

0.gif

Core part code:

Layout:activity_main.xml

                            

Get data class:GetData.java:

/**
 * Created by Jay on 2015/9/7 0007.
 */
public class GetData {
    // 定义一个获取网络图片数据的方法:
    public static byte[] getImage(String path) throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        // 设置连接超时为5秒
        conn.setConnectTimeout(5000);
        // 设置请求类型为Get类型
        conn.setRequestMethod("GET");
        // 判断请求Url是否成功
        if (conn.getResponseCode() != 200) {
            throw new RuntimeException("请求url失败");
        }
        InputStream inStream = conn.getInputStream();
        byte[] bt = StreamTool.read(inStream);
        inStream.close();
        return bt;
    }

    // 获取网页的html源代码
    public static String getHtml(String path) throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        if (conn.getResponseCode() == 200) {
            InputStream in = conn.getInputStream();
            byte[] data = StreamTool.read(in);
            String html = new String(data, "UTF-8");
            return html;
        }
        return null;
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private TextView txtMenu, txtshow;
    private ImageView imgPic;
    private WebView webView;
    private ScrollView scroll;
    private Bitmap bitmap;
    private String detail = "";
    private boolean flag = false;
    private final static String PIC_URL = "http://ww2.sinaimg.cn/large/7a8aed7bgw1evshgr5z3oj20hs0qo0vq.jpg";
    private final static String HTML_URL = "http://www.baidu.com";

    // 用于刷新界面
    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case 0x001:
                    hideAllWidget();
                    imgPic.setVisibility(View.VISIBLE);
                    imgPic.setImageBitmap(bitmap);
                    Toast.makeText(MainActivity.this, "图片加载完毕", Toast.LENGTH_SHORT).show();
                    break;
                case 0x002:
                    hideAllWidget();
                    scroll.setVisibility(View.VISIBLE);
                    txtshow.setText(detail);
                    Toast.makeText(MainActivity.this, "HTML代码加载完毕", Toast.LENGTH_SHORT).show();
                    break;
                case 0x003:
                    hideAllWidget();
                    webView.setVisibility(View.VISIBLE);
                    webView.loadDataWithBaseURL("", detail, "text/html", "UTF-8", "");
                    Toast.makeText(MainActivity.this, "网页加载完毕", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    break;
            }
        }

        ;
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setViews();
    }

    private void setViews() {
        txtMenu = (TextView) findViewById(R.id.txtMenu);
        txtshow = (TextView) findViewById(R.id.txtshow);
        imgPic = (ImageView) findViewById(R.id.imgPic);
        webView = (WebView) findViewById(R.id.webView);
        scroll = (ScrollView) findViewById(R.id.scroll);
        registerForContextMenu(txtMenu);
    }

    // 定义一个隐藏所有控件的方法:
    private void hideAllWidget() {
        imgPic.setVisibility(View.GONE);
        scroll.setVisibility(View.GONE);
        webView.setVisibility(View.GONE);
    }

    @Override
    // 重写上下文菜单的创建方法
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        MenuInflater inflator = new MenuInflater(this);
        inflator.inflate(R.menu.menus, menu);
        super.onCreateContextMenu(menu, v, menuInfo);
    }

    // 上下文菜单被点击是触发该方法
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.one:
                new Thread() {
                    public void run() {
                        try {
                            byte[] data = GetData.getImage(PIC_URL);
                            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(0x001);
                    }

                    ;
                }.start();
                break;
            case R.id.two:
                new Thread() {
                    public void run() {
                        try {
                            detail = GetData.getHtml(HTML_URL);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(0x002);
                    };
                }.start();
                break;
            case R.id.three:
                if (detail.equals("")) {
                    Toast.makeText(MainActivity.this, "先请求HTML先嘛~", Toast.LENGTH_SHORT).show();
                } else {
                    handler.sendEmptyMessage(0x003);
                }
                break;
        }
        return true;
    }
}

Finally don’t forget to add network permissions:


Notes

There is no need to explain the reason for using handler~ In addition, when we load html code, we use webView's loadDataWithBaseURL instead of LoadData. If you use LoadData and you have to worry about the problem of Chinese garbled characters, so... you don't have to worry so much by using loadDataWithBaseURL. In addition, some pages may require us to submit some parameters, such as account and password: we only need to splice the corresponding parameters to the end of the URL, such as: http://192.168.191.1:8080/ComentServer/LoginServlet?passwd=123&name=Jack Then the server side getParamater("passwd") can get the corresponding parameters. These things will be clearly visible when we request. , so the GET method is not safe! Another thing to note is that Android does not allow UI operations in non-UI threads starting from 4.0!


2) HttpURLConnection sends POST request code example

With GET, there is naturally POST. The HttpURLConnection we obtain through openConnection performs Get requests by default. Therefore, when we use POST to submit data, we should set the relevant parameters in advance: conn.setRequestMethod("POST"); There are also: conn.setDoOutput(true); conn.setDoInput(true); Set allowed input and output Also: conn.setUseCaches(false); The POST method cannot be cached and must be set to false manually. See the code for specific implementation:

Running renderings:

2.gif

##Core code:

PostUtils.java

public class PostUtils {
    public static String LOGIN_URL = "http://172.16.2.54:8080/HttpTest/ServletForPost";
    public static String LoginByPost(String number,String passwd)
    {
        String msg = "";
        try{
            HttpURLConnection conn = (HttpURLConnection) new URL(LOGIN_URL).openConnection();
            //设置请求方式,请求超时信息
            conn.setRequestMethod("POST");
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(5000);
            //设置运行输入,输出:
            conn.setDoOutput(true);
            conn.setDoInput(true);
            //Post方式不能缓存,需手动设置为false
            conn.setUseCaches(false);
            //我们请求的数据:
            String data = "passwd="+ URLEncoder.encode(passwd, "UTF-8")+
                    "&number="+ URLEncoder.encode(number, "UTF-8");
            //这里可以写一些请求头的东东...
            //获取输出流
            OutputStream out = conn.getOutputStream();
            out.write(data.getBytes());
            out.flush();
             if (conn.getResponseCode() == 200) {  
                    // 获取响应的输入流对象  
                    InputStream is = conn.getInputStream();  
                    // 创建字节输出流对象  
                    ByteArrayOutputStream message = new ByteArrayOutputStream();  
                    // 定义读取的长度  
                    int len = 0;  
                    // 定义缓冲区  
                    byte buffer[] = new byte[1024];  
                    // 按照缓冲区的大小,循环读取  
                    while ((len = is.read(buffer)) != -1) {  
                        // 根据读取的长度写入到os对象中  
                        message.write(buffer, 0, len);  
                    }  
                    // 释放资源  
                    is.close();  
                    message.close();  
                    // 返回字符串  
                    msg = new String(message.toByteArray());  
                    return msg;
             }
        }catch(Exception e){e.printStackTrace();}
        return msg;
    }
}

PS: Because MyEclipse is not installed on the computer and time is limited, I won’t write another demo. I will use the previous Eclipse demo! In fact, it is enough to look at the core code directly~ Code download:

HttpURLConnection example.zip


4. Handling Cookie issues

Before talking about this, we must first understand two concepts:

Session and CookieCookie is just a common form of Session mechanism. We can also use other methods as a unique identifier for the client. This is determined by the server, and the only thing that can prove it is a client ID! In addition to this method, we can also use URL rewriting! Ways to do it! So don’t stupidly tell others in the future: Session is not just a cookie!

The following is an example to help you understand this Cookie: Xiaozhu entered the account and password to log in to the school's educational system, and then successfully accessed the class schedule information. Then if you are using Chrome, press F12 to enter development mode: Go to the Resources interface and you can see our Cookies:

3.png

After clicking, we can see the content saved in it. , consisting of name; value; domain where the cookie is located; The directory where the cookie is located (path) Asp.net defaults to /, which is the root directory; expiration time; Cookie size:

We can see that there is a Cookie field in the request header:

4.png

Well, now we clear the cookies (or wait a few minutes), and then visit the following link:

5.png

At this time, the page automatically jumped back to the login page! Of course, some other websites may pop up a dialog box saying Something like "login timeout"!

Summary of a simple process of Http request login: Generally when logging in: the server returns a Cookie through the Set-Cookie response header, and the browser saves this Cookie by default. This cookie will be brought with you when you visit relevant pages later, and the visit will be completed through the Cookie request header. If there is no cookie or If the cookie expires, it will prompt the user not to log in, the login has timed out, and information such as login is required for access!

And when we use HttpClient and HttpURLConnection, we actually simulate this process and get the cookie after logging in. Take it to send the request: The key code is as follows: Get Cookie:conn.getHeaderField("Set-Cookie");Bring Cookie when requesting:conn.setRequestProperty("Cookie",cookie);

In addition, in addition to this way of setting request headers, another compromise method can be used: URL rewriting: On the basis of the original request link, a parameter such as...&sessionid=xxxxx is added, and then the server parses it. judge!

Here we use the form of JSON string. When receiving the request, the server takes out the content in the session and then makes a query~


5. Using HttpURLConnection to send PUT requests

Put requests may be a bit unfamiliar to many friends. After all, the situations we usually come into contact with most are GET and POST. Xiaozhu didn’t know it at first, but later I discovered that it is actually similar to POST, and we only need to modify it based on POST. Just order something and it’s ready to go! And HttpClient also provides us with an HttpPut API. Below is the request code written in Xiaozhu’s own project:

public static String LoginByPut(Context mContext, String mobile, String password, int from, 
          String devid,String version_name, int remember_me) {
    String resp = "";
    try {
        HttpURLConnection conn = (HttpURLConnection) new URL(LOGIN_URL).openConnection();
        conn.setRequestMethod("PUT");
        conn.setReadTimeout(5000);
        conn.setConnectTimeout(5000);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setUseCaches(false);

        String data = "mobile=" + mobile + "&password=" + password + "&from=" + from + "&devid=" + "devid"
                + "&version_name=" + "version_name" + "&remember_me=" + remember_me;
        ;
        // 获取输出流:
        OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
        writer.write(data);
        writer.flush();
        writer.close();

        // 获取相应流对象:
        InputStream in = conn.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null)
            response.append(line);
        SPUtils.put(mContext, "session", conn.getHeaderField("Set-Cookie"));
        // 资源释放:
        in.close();
        // 返回字符串
        Log.e("HEHE", response.toString());
        return response.toString();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "";
}

Summary of this section:

Okay, this section is about the use of HttpUrlConnection. At this point, in addition, most of the HTTP section comes from Xiaozhu A small collection I wrote before Http Communication for Android. If you have read this series, you can skip this section. Most of the content is the same! Well, that’s all, thank you~