Méthode de requête HTTP Android : HttpURLConnection


Introduction à cette section :

Ce que nous avons étudié dans les deux sections précédentes étaient des éléments conceptuels, le protocole HTTP et certains éléments de l'en-tête du protocole, et dans cette section, nous Il est temps d'accumuler le code, et cette section concerne l'une des méthodes de requête HTTP fournies par Android : HttpURLConnection. En plus de cela, il existe un autre type de HttpClient, dont nous parlerons dans la section suivante ! Cependant, lorsque la demande devient compliquée, la première peut être utilisée C'est très gênant, et ce dernier est souvent utilisé par nous dans la capture de paquets Java. Après tout, ce n'est pas le propre fils de Google, mais en version 4.4. HttpURLConnection a été remplacé par OkHttp ! Eh bien, pour suivre le rythme de mon temps, j'ai décidé d'en parler après avoir parlé de HttpClient. OkHttp ! À propos, nous n’utilisons généralement pas HttpURLConnection et HttpClient dans le développement réel, mais nous en utilisons d’autres pour les encapsuler. De bons frameworks de requêtes réseau tiers, tels que : Volley, android-async-http, loopj, etc., car les opérations réseau impliquent L'asynchrone et le multi-threading sont très gênants si vous le faites vous-même, donc pour le développement réel, vous devez directement faire appel à un tiers ! ! Bien sûr, j'étudierai aussi Peu importe, après tout, le tiers est également bâti sur ces fondations, avec une architecture de qualité et diverses optimisations ! Bon, sans plus tarder, commençons Contenu de cette section!


1. Introduction à HttpURLConnection

Réponse : Un client HTTP polyvalent et léger qui peut être utilisé pour effectuer la plupart des opérations HTTP. Bien que l'API fournie par HttpURLConnection soit relativement simple, elle nous facilite également l'utilisation. Utilisez-le et prolongez-le. Hérite de URLConnection, une classe abstraite, et ne peut pas instancier directement des objets. En appelant openCollection() Méthode pour obtenir une instance d'objet, la valeur par défaut est avec la compression gzip ;


2 Étapes pour utiliser HttpURLConnection

Les étapes pour utiliser HttpURLConnection sont les suivantes :

.
  • Créer un objet URL : URL url = new URL(http://www.baidu.com);
  • Appeler openConnection() de l'URL object Pour obtenir l'instance de l'objet HttpURLConnection : HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  • Définissez la méthode utilisée pour les requêtes HTTP : GET ou POST, ou d'autres méthodes de requête telles que : PUTconn.setRequestMethod("GET");
  • Définissez le délai d'expiration de la connexion, le nombre de millisecondes pour le délai d'expiration de lecture et certains en-têtes de message que le serveur espère obtenir conn.setConnectTimeout(6*1000); conn.setReadTimeout(6 * 1000);
  • Appelez la méthode getInputStream() pour obtenir le flux d'entrée renvoyé par le serveur, et puis lisez le flux d'entrée InputStream in = conn .getInputStream();
  • Enfin, appelez la méthode disconnect() pour fermer la connexion HTTPconn.disconnect();

PS : En plus de ce qui précède, nous pouvons parfois également avoir besoin de juger le code de réponse, tel que 200 : if(conn.getResponseCode() != 200) puis un peu de traitement Aussi, peut-être parfois nous. Il n'est pas nécessaire de passer de paramètres, mais pour accéder directement à une page, on peut directement utiliser : final InputStream in = new URL("url").openStream(); Lisez ensuite le flux directement, mais cette méthode convient pour un accès direct à la page. L'implémentation sous-jacente est en fait. renvoie openConnection().getInputStream(), et nous ne pouvons pas encore en définir C’est juste une demande, vous devez donc la peser vous-même si vous voulez l’écrire comme ça !


3. Exemples d'utilisation de HttpURLConnection

Ici, nous écrivons principalement deux exemples d'utilisation différents pour les requêtes GET et POST. Nous pouvons conn.getInputStream(). Ce qui est obtenu est un flux, nous devons donc écrire une classe pour convertir le flux en tableau binaire ! La classe d'outils est la suivante :

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();
    }
}

Maintenant, nous pouvons commencer à jouer avec nos exemples !


1) HttpURLConnection envoie un exemple de code de requête GET

Exécution de rendus :

0.gif

Code de la pièce principale :

Mise en page : activity_main.xml

                            

Obtenir la classe de données : 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;
    }
}

Enfin, n'oubliez pas d'ajouter les autorisations réseau :


Notes

Il n'est pas nécessaire d'expliquer la raison de l'utilisation du gestionnaire ~ De plus, nous utilisons loadDataWithBaseURL de webView au lieu de LoadData pour charger le code html. Si vous utilisez LoadData et que vous devez vous soucier du problème des caractères chinois tronqués, alors... vous n'avez pas à vous inquiéter autant en utilisant loadDataWithBaseURL. De plus, certaines pages peuvent nous demander de soumettre certains paramètres, tels que le compte et le mot de passe : il suffit de coller les paramètres correspondants à la fin de l'URL, tels que : http://192.168.191.1:8080/ComentServer/LoginServlet?passwd=123&name=Jack Ensuite, le côté serveur getParamater("passwd") peut obtenir les paramètres correspondants. Ces éléments seront clairement visibles lorsque nous le demanderons. , donc la méthode GET n'est pas sûre ! Une autre chose à noter est qu'Android n'autorise pas les opérations d'interface utilisateur dans les threads non-UI à partir de la version 4.0


2) HttpURLConnection envoie un exemple de code de requête POST

Avec GET, il y a naturellement POST. La HttpURLConnection que nous obtenons via openConnection effectue les requêtes Get par défaut. Par conséquent, lorsque nous utilisons POST pour soumettre des données, nous devons définir les paramètres pertinents à l'avance : conn.setRequestMethod("POST"); Il existe également : conn.setDoOutput(true); conn.setDoInput(true); Aussi : conn.setUseCaches(false); La méthode POST ne peut pas être mise en cache et doit être définie manuellement sur false. Voir le code pour une implémentation spécifique :

Exécution des rendus :

2.gif

Code principal :

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 : Comme MyEclipse n'est pas installé sur l'ordinateur, et en raison de contraintes de temps, je n'écrirai pas une autre démo, je l'utiliserai. démo du précédent Eclipse! En fait, il suffit de regarder directement le code principal~ Téléchargement du code : HttpURLConnection example.zip


4. Gestion des problèmes de cookies

Avant de parler de cela, nous devons d'abord comprendre deux concepts : Session et CookieLe cookie n'est qu'une forme courante de mécanisme de session. Nous pouvons également utiliser d'autres méthodes comme identifiant unique pour le client. Ceci est déterminé par le serveur, et la seule chose qui peut le prouver est un identifiant client ! En plus de cette méthode, on peut également utiliser la réécriture d’URL ! Façons de le faire ! Alors ne dites pas bêtement aux autres à l’avenir : la session n’est pas qu’un cookie !

Ce qui suit est un exemple pour vous aider à comprendre ce cookie : Xiaozhu a saisi le compte et le mot de passe et s'est connecté au système d'administration académique de l'école, puis a réussi à accéder aux informations sur l'horaire des cours. Ensuite si vous utilisez Chrome, appuyez sur F12 pour passer en mode développement : Allez dans l'interface Ressources et vous pourrez voir nos Cookies :

3.png

Après avoir cliqué, nous pouvons voir le contenu enregistré dans celui-ci , composé du nom ; de la valeur ; du domaine où se trouve le cookie ; Le répertoire où se trouve le cookie (chemin) Asp.net est par défaut /, qui est le répertoire racine ; Taille du cookie :

Nous pouvons voir qu'il y a un champ Cookie dans l'en-tête de la requête :

4.png

Eh bien, maintenant nous effaçons les cookies (ou attendons quelques minutes), puis visitons le lien suivant :

5.png

À cette fois, la page est automatiquement revenue à la page de connexion ! Bien sûr, certains autres sites Web peuvent afficher une boîte de dialogue indiquant Quelque chose comme « délai d'expiration de connexion » !

Résumez un processus simple de connexion par demande HTTP : Généralement lors de la connexion : le serveur renvoie un Cookie via l'en-tête de réponse Set-Cookie, et le navigateur enregistre ce Cookie par défaut. Ce cookie sera apporté avec vous lorsque vous visiterez ultérieurement les pages concernées, et la visite sera complétée via l'en-tête de demande de cookie s'il n'y a pas de cookie ou. Si le cookie expire, il invitera l'utilisateur à ne pas se connecter, la connexion a expiré et des informations telles que la connexion sont requises pour l'accès !

Et lorsque nous utilisons HttpClient et HttpURLConnection, nous simulons ce processus et obtenons le cookie après la connexion. Prenez-le pour envoyer la demande : Le code clé est le suivant : Obtenir un cookie : conn.getHeaderField("Set-Cookie");Apportez un cookie lors de la demande : conn.setRequestProperty("Cookie",cookie);

De plus, en plus de cette manière de paramétrer les en-têtes de requêtes, une autre méthode de compromis peut être utilisée : Réécriture d'URL : Sur la base du lien de demande d'origine, un paramètre tel que...&sessionid=xxxxx est ajouté, puis le serveur l'analyse. juge!

Ici nous utilisons la forme de chaîne JSON Lors de la réception de la requête, le serveur sort le contenu de la session puis fait une requête~


5. HttpURLConnection pour envoyer des requêtes PUT

Les requêtes Put peuvent être un peu inconnues pour de nombreux amis. Après tout, les situations avec lesquelles nous sommes habituellement en contact sont GET et POST. Xiaozhu ne le savait pas au début, mais plus tard, j'ai découvert qu'il est en fait similaire au POST et qu'il suffit de le modifier en fonction du POST. Commandez simplement quelque chose et c’est prêt à partir ! Et HttpClient nous fournit également une API HttpPut. Vous trouverez ci-dessous le code de requête écrit dans le propre projet de Xiaozhu :

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

Résumé de cette section :

D'accord, cette section concerne l'utilisation de HttpUrlConnection. sur ce point, en plus, la majeure partie de la section HTTP vient de Xiaozhu Une petite collection que j'ai écrite auparavant Http Communication pour Android Si vous avez lu cette série, vous pouvez ignorer cette section. Même! Eh bien, c'est tout, merci~