二营长的意大利炮手

二营长的意大利炮手

一、网络的基本概念及Http协议

IP地址和端口号

  • IP地址:网络中的媚态计算机都必须一个唯一的IP地址作为标识,用一组由“.”分隔的十进制数组成
  • 端口号:IP地址只能保证键数据送到指定的计算机,但无法知道交给该主机的哪个网络程序,因此采用端口号标识计算机上正在运行的进程
  • 每个被发送的网略数据包都包含端口号,用于将该数据帧交给具有相同端口号的应用程序处理

Java的网络编程由Java.net包中的类进行处理

  • InetAddress类:描述IP地址

HTTP协议

  • 属于应用层的面向对象的协议,适用于分布式超媒体信息系统

  • 主要特点

    1、支持C/S模式

    2、简单快速:只需传送请求方法和路径,请求方法常用的有:GET、HEAD、POST等

    3、灵活:允许传输任意类型的数据对象,用Content-Type进行标记

    4、无连接:限制每次连接只处理一个请求

    5、无状态:对事务处理没有记忆功能

  • HTTP的URL的格式:

    1、http://host[:port][/path]

    2、http表示要通过HTTP协议来定位网络资源;host表示合法的Internet主机域名或者IP地址;port指定一个端口号,为空则使用默认端口80;path指定请求资源的URI

HTTP请求报文

  • 由请求行、请求报头、空行和请求数据4个部分组成

HTTP相应报文

  • 由状态行、消息报头、空行、相应正文组成

常见的状态码

  • 200 OK:客户端请求成功
  • 400 Bad Request:客户端请求有语法错误,不能被服务器所理解
  • 400 Unauthorized:请求未经授权,这个状态码必须和WWW-Authenticate报头域一起使用
  • 403 Forbidden:服务器收到请求,但是拒绝提供服务
  • 404 Not Found:服务器无法根据客户端的请求找到资源
  • 500 Internal Server Error:服务器发生不可预期的错误
  • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常

https请求

  • HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,也就是HTTP的安全版
  • HTTPS=HTTP+SSL/TLS
  • HTTPS的安全基础是SSL

二、Android的网络编程

Android的网络编程

1、HTTP通信方式

HttpURLConnection

  • Android 2.3之后,HttpURLConnection是Android网络编程的最佳选择,它的API简单,体积较小,压缩和缓存机制有效较少网络访问的流量

HttpClient

  • 开发团队向开发者建议:在Android 2.2版本及以下可以使用HttpClient,在2.3以上版本则应该使用HttpURLConnection
  • Android 6.0直接删除了HttpClient类库

2、Socket通信方式

Android P的http网络请求的问题

Android p要求默认使用加密连接,禁止APP使用任何未加密的连接,因此需要使用TLS传输层安全协议,也就是Https

Android P使用HttpUrlConnection进行http的get请求会出现以下异常

  • W/System.err:java.io.IOException:Cleartext HTTP traffic to **** not permitted

解决方案

  • 推荐:使用Https连接
  • targetSdkVersion降到27级以下版本
  • 更改网络安全配置,此更改与网站有关,有时不能得到相应

更改网络安全配置

在res新增xml目录,创建network_security_config.xml,开启http请求

 <network-security-config>
 <base-config cleartextTrafficPermitted="true"/>
 </network-security-config>

在AndroidMainfest.xml中的application标签增加以下属性

  • android:networkSecurityConfig="@xml/network"
    

Android的Https

自定义X509TrustManager

  • 在使用HttpsURLConnection发起HTTPS请求的时候,提供了一个自定义的X509TrustManager,未实现安全校验逻辑
  • 如果不提供自定义X509TrustManager,代码运行起来可能会报异常

自定义HostnameVerifier

  • 在握手期间,如果URL的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此链接

URL类

1、统一资源定位符(URL)是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址

2、互联网上的每个文件都有一个唯一的URL

3、URL类提供了多个构造器用于创建URL对象

4、URL类提供多个方法访问URL对应的资源:

  • URLConnection openConnection():返回一个URLConnection对象,它表示到URL所引用的远程对象的连接
  • InputStream openStream():打开此URL的连接,并返回一个用于读取该URL资源的InputStream

Android URL通信

1、Android HTTP URL接口的基本操作包括:

  • 创建URL以及HttpURLConnection对象
  • 连接参数设置
  • 连接到服务器
  • 向服务器写数据
  • 从服务器读取数据

2、HttpURLConnection的属性设置

    connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestMethod(method);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);
        if("POST".equals(method)){
            connection.setDoOutput(true);
        }

3、HttpURLConnection访问HTTP资源的步骤:

(1)根据URL地址创建URL对象

(2)使用URL对象的openConnection()方法获取HttpURLConnection对象

(3)设置连接的属性,包括GET/POST请求方式

(4)输入、输出数据

(5)关闭输入、输出流

(6)在AndroidManifest配置文件中设置访问INTERNET的权限

4、GET方式

  // 1、将url字符串转为URL对象
        URL url = new URL(urlPath);
 //            2、获得HttpURLConnection对象
        connection = (HttpURLConnection) url.openConnection();
//            3、设置连接的相关参数
        connection.setRequestMethod("GET");
        connection.setUseCaches(false);
        connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);

  //            4、配置https的证书
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(
                    HttpsUtil.getSSLSocketFactory());
        }
   //            5、进行数据的读取,首先判断响应码是否为200
        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
    //                获得输入流
            is = connection.getInputStream();
    //                包装字节流为字符流
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
   //                读取数据
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
   //                6、关闭资源
            is.close();
            connection.disconnect();
  //                7、返回结果
            return response.toString();

5、POST方式

  String body=getParamString(params);
        byte[] data=body.getBytes();

        URL url=new URL(urlPath);

        connection= (HttpsURLConnection) url.openConnection();
        //            3、设置连接的相关参数
        connection.setRequestMethod("POST");
        connection.setUseCaches(false);
        connection.setConnectTimeout(15000);
        connection.setReadTimeout(15000);
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        connection.setDoInput(true);
        connection.setDoOutput(true);

  //            4、配置https的证书
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ((HttpsURLConnection) connection).setSSLSocketFactory(
                    HttpsUtil.getSSLSocketFactory());
        }
        connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
        connection.setRequestProperty("Content-Length",String.valueOf(data.length));
        OutputStream os=connection.getOutputStream();
        os.write(data);
        os.flush();

        if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){

           is=connection.getInputStream();
           BufferedReader reader=new BufferedReader(new InputStreamReader(is));
            //                读取数据
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
 //                6、关闭资源
            is.close();
            connection.disconnect();
 //                7、返回结果
            return response.toString();
        }

6、HttpURLConnection使用的注意事项

  • 使用setConnectTimeout()方法设置连接超时,当网络不好使,Android系统会在超时设置时间后收回资源,中断操作
  • 通过getResponseCode()对响应码进行判断,如果返回的相应码为200,则表示连接成功
  • 在对大文件操作时,要将文件写道SDCard上,不要直接写到手机内存上
  • 操作大文件时,要一边从网络上读取,一边往SDCard上写入,减少手机内存的使用
  • 对文件流操作完毕后要及时关闭
  • Android4.0后所有网络通信的操作都不能在主线程进行,需要使用独立的线程完成

OKHttp

  • 官网:square.github.io/okhttp/

  • 源码:github.com/square/okht…

  • 配置:

    1. OKHttp是Android 2.3及其以上版本,Java要求JDK1.7以上

    2. 添加依赖:

      implementation 'com.squareup.okhttp3:okhttp:4.2.1'
      
    3. 添加权限:

        <uses-permission android:name="android.permission.INTERNET"/>
      
  • 特点:

    1. 0KHttp是Android版Http喀户端,非常高效,支持SPDY、连接池、GZIP和HTTP缓存。
    2. 默认情况下,0KHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题。
    3. 如果应用程序集成了0KHttp,Retrofit默认会使用0KHttp处理其他网络层请求。
    4. 从Android4.4开始,HttpURLConnection的底层实现采用了okHttp。
  • OkHttp开发基本思路

    1. 0kHttp的每次网络请求是一个Request,提供Request必要的参数url、header等,基于Request构造出一个Call对象,再调用它的execute( )方法,就能取得WebServer回复的数据。
    2. 如果同步调用,需要在独立的线程中执行,使佣异步调用,则采用回调的方式执行,在内部封装了一个请求队列。
    3. OkHttp依赖另一个组件okiO完成高性能的I/O操作
    4. 基本用法:新建一个OkHttpClient对象;通过Request.Builder对象新建一个Request对象;通过Request对象构造Call对象,调用enqueue()以异步的方式将call加入调度队列,等待request执行完成;通过Call对象的Callback对象返回执行结果。
    5. 一直等待http请求,直到返回响应,请求期间会阻塞进程,因此不能在Android的主线程执行,需要用Android的多线程方式进行处理,否则会报错。
  • Get同步请求

    1. 当HTTP响应码位于200到300之间时,认为操作是成功的
    2. response.body()返回-个ResponseBody对象,封装了HTTP响应的主体数据,它的string()方法将这些数据转换为字符串,另一个byteStream()方法则返回一个InputStream流
    3. 注意事项:要独立的线程中执行网络操作;对于超过1MB的响应body,应使用流的方式来处理body。
    4. 一般不适用
  • Get异步请求

    1. 在另外的工作线程中执行http请求,请求时不会阻塞当前的线程,所以可以在Android主线程中使用。
    2. 异步请求需要加入到一个请求队列中,并且要指定回调方法。
  • post异步请求

    1.通过RequestBody构建请求数据

    private void postForm(String url){
    RequestBody formBody = new FormBody.Builder().add("city","南京").build();
     Request request = new Request. Builder().url(url).post(formBody).build();
    mClient.newCall(request).enqueue(new Callback(){
    @Override
    public void onResponse(Call call, Response response) throws IOException {
    final String str = response .body().string();
    Log.d(TAG, str);
    runOnUiThread(new Runnable() {
      @Override
     public void run() {
     textView. setText(str);
    });
    }
    @Override
    public void onFailure(Call call,   IOException e) {
     });
    }
    
  • 图片加载框架Glide

    1. 添加依赖:

      implementation 'com.github.bumptech.glide:glide:4.10.0'
      annotationProcessor 'com. github.bumptech.glide:compiler:4.10.0'
       //https图片处理
      implementation "com.github.bumptech.glide:okhttp3-integration:4.10.0"
      
      
    2. 添加网络权限:

      <uses-permission android: name= "android. permi ssion . INTERNET" />
      
      
    3. 使用:

      Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
      
      
    4. 加载图片的一般方法:

      Glide.with(Context context).load(String url).into(ImageView imageView);
      
      
  • Glide加载https图片

    1. 创建支持https的OkHttpClient对象:

      public static 0kHttpClient handleSSLHandshakeBy0kHttp() {
      return new 0kHttpClient.Builder()
      .connectTimeout(10,TimeUnit. SECONDS)
      .writeTimeout(10,TimeUnit. SECONDS)
      .readTimeout(10,TimeUnit . SECONDS)
       //支持HTTPS请求,跳过证书验i证
      .sslSocketFactory(getSSLSocketFactory(),(X509TrustManager) getTrustManager()[0])
      .hostnameVerifier(new TrustAllHostnameVerifier())
      .build();
      }
      
    2. 创建继承AppGlidModule类的自定义类,重写registerComponents( )方法:

      @GlideModule
      public class OkHttpGlideModule extends AppGlideModule {
       @Override
       public void registerComponents( @NonNull Context context,
       @NonNull Glide glide,@NonNull Registry registry) {
      OkHttpClient client = HttpsUtil.handl esSLHandshakeByokHttp();
       registry.replace(GlideUrl.class,InputStream.class,
       new 0kHttpUrlLoader.Factory(client));
       }
      }
      

今年年初我花一个月的时间收录整理了一套知识体系,如果有想法深入的系统化的去学习的,可以点击传送门,我会把我收录整理的资料都送给大家,帮助大家更快的进阶。

Android网络编程详解-LMLPHP

11-16 12:26