49.HTTP下载数据

49.网络通信-超文本传输HTTP-下载数据


49.1 知识点

Head请求类型检测资源可用性

利用 Head 请求类型,获取信息

try
{
    // 尝试执行以下操作,捕获可能的异常
    // 在这里,我们尝试获取远程服务器上文件的信息
    
    // 1. 创建 HTTP 通讯用连接对象 HttpWebRequest 对象
    HttpWebRequest httpWebRequest = HttpWebRequest.Create(new Uri("http://192.168.1.101:8000/HTTPRoot/pic.png")) as HttpWebRequest;
    
    // 2. 设置请求类型或其他相关参数
    httpWebRequest.Method = WebRequestMethods.Http.Head; // 使用 HTTP HEAD 请求方法
    httpWebRequest.Timeout = 2000; // 设置请求超时时间为 2 秒
    
    // 3. 发送请求,获取响应结果 HttpWebResponse 对象
    HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
    
    // 检查响应的状态码
    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
    {
        // 如果状态码为 200 (OK),表示文件存在且可用
        print("文件存在且可用");
        print(httpWebResponse.ContentLength); // 打印文件大小
        print(httpWebResponse.ContentType); // 打印文件的 MIME 类型
        
        httpWebResponse.Close(); // 关闭响应对象,释放资源
    }
    else
    {
        // 如果状态码不是 200,文件不能用,打印状态码
        print("文件不能用" + httpWebResponse.StatusCode);
    }
}
catch (WebException w)
{
    // 捕获 WebException 异常,通常表示网络请求出错
    print("获取出错" + w.Message + w.Status); // 打印错误消息和状态信息
}

Get请求类型下载资源

利用 Get 请求类型,下载资源

try
{
    // 尝试执行以下操作,捕获可能的异常
    // 在这里,我们尝试下载远程文件到本地
    
    // 1. 创建 HTTP 通讯用连接对象 HttpWebRequest 对象
    HttpWebRequest httpWebRequest = HttpWebRequest.Create(new Uri("http://192.168.1.101:8000/HTTPRoot/pic.png")) as HttpWebRequest;
    
    // 2. 设置请求类型或其他相关参数
    httpWebRequest.Method = WebRequestMethods.Http.Get; // 使用 HTTP GET 请求方法
    httpWebRequest.Timeout = 3000; // 设置请求超时时间为 3 秒
    
    // 3. 发送请求,获取响应结果 HttpWebResponse 对象
    HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
    
    // 4. 获取响应数据流,写入本地路径
    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
    {
        // 打印本地数据存储路径
        print("本地存储路径:" + Application.persistentDataPath);
        
        // 创建本地文件流以将下载的数据写入本地
        using (FileStream fileStream = File.Create(Application.persistentDataPath + "/httpPic.png"))
        {
            Stream downloadResponseStream = httpWebResponse.GetResponseStream();
            byte[] bytes = new byte[2048];
            
            // 读取数据
            int contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);
            
            // 一点一点地写入本地
            while (contentLength != 0)
            {
                fileStream.Write(bytes, 0, contentLength);
                contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);
            }
            
            fileStream.Close();
            downloadResponseStream.Close();
            httpWebResponse.Close();
        }
        // 打印下载成功消息
        print("下载成功");
    }
    else
    {
        // 如果状态码不是 200 (OK),下载失败,打印状态码
        print("下载失败,状态码:" + httpWebResponse.StatusCode);
    }
}
catch (WebException w)
{
    // 捕获 WebException 异常,通常表示网络请求出错
    print("下载出错,状态:" + w.Status + ",错误消息:" + w.Message);
}

测试结果

Get 请求类型携带额外信息

我们在进行 HTTP 通信时,可以在地址后面加一些额外参数传递给服务端。一般在和短连接游戏服务器通讯时,需要携带额外信息。

举例:

这个链接可以分成几部分:

  1. 协议部分:取决于服务器端使用的哪种协议

    • http:// —— 普通的 HTTP 超文本传输协议
    • https:// —— 加密的超文本传输协议
  2. 域名部分:

  3. 端口部分:

    • 8080
    • 可以不写,如果不写默认为 80
  4. 虚拟目录部分:

    • news/child/
    • 域名后的 / 开始,到最后一个 / 之前的部分
  5. 文件名部分:

    • index.asp
    • ?之前的最后一个 / 后的部分
  6. 参数部分:

    • boardID=5&ID=24618&page=1
    • ?之后的部分就是参数部分,多个参数一 & 分隔开
    • 这里有三个参数
      • boardID = 5
      • ID = 24618
      • page = 1

我们在和服务端进行通信时,只要按照这种规则格式进行通信,就可以传递参数给对象。主要可用于:

  • web 网站服务器
  • 游戏短连接服务器

总结

  1. Head 请求类型

    • 主要用于获取文件的一些基础信息,可以用于确定文件是否存在。
  2. Get 请求类型

    • 主要用于传递信息给服务器,用于获取具体信息。
    • 服务器返回的信息,可以通过 Response 中的流来获取。
    • 用 Get 请求时,可以在连接中携带一些额外参数(在链接后面加上 ? 参数名=参数值&参数名=参数值&参数名=参数值&…)。
    • 正常的 HTTP 服务器应用程序,都会去解析 Get 请求时连接中的参数进行逻辑处理(后端程序的工作)。
    • 我们主要要掌握的知识点:
      • 额外参数按格式书写
      • 通过 Response 对象中的流来获取返回的数据(数据的类型多种多样,可以是文件、自定义消息等等,我们按照规则解析即可)。
  3. 在和 HTTP 服务器通信时,我们经常会使用额外参数的形式传递信息,特别是以后和一些运营平台对接时。

  4. 文件下载功能和 Ftp 非常类似,只是其中使用的类、协议、请求类型不同而已。


49.2 知识点代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using UnityEngine;

public class Lesson49_网络通信_超文本传输HTTP_下载数据 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 检测资源可用性

        //利用Head请求类型,获取信息
        try
        {
            // 尝试执行以下操作,捕获可能的异常
            // 在这里,我们尝试获取远程服务器上文件的信息

            // 1. 创建HTTP通讯用连接对象HttpWebRequest对象
            HttpWebRequest httpWebRequest = HttpWebRequest.Create(new Uri("http://192.168.1.101:8000/HTTPRoot/pic.png")) as HttpWebRequest;

            // 2. 设置请求类型或其他相关参数
            httpWebRequest.Method = WebRequestMethods.Http.Head; // 使用HTTP HEAD请求方法
            httpWebRequest.Timeout = 2000; // 设置请求超时时间为2秒

            // 3. 发送请求,获取响应结果HttpWebResponse对象
            HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

            // 检查响应的状态码
            if (httpWebResponse.StatusCode == HttpStatusCode.OK)
            {
                // 如果状态码为200 (OK),表示文件存在且可用
                print("文件存在且可用");
                print(httpWebResponse.ContentLength); // 打印文件大小
                print(httpWebResponse.ContentType); // 打印文件的MIME类型

                httpWebResponse.Close(); // 关闭响应对象,释放资源
            }
            else
            {
                // 如果状态码不是200,文件不能用,打印状态码
                print("文件不能用" + httpWebResponse.StatusCode);
            }
        }
        catch (WebException w)
        {
            // 捕获WebException异常,通常表示网络请求出错
            print("获取出错" + w.Message + w.Status); // 打印错误消息和状态信息
        }

        #endregion

        #region 知识点二 下载资源

        //利用Get请求类型,下载资源
        try
        {
            // 尝试执行以下操作,捕获可能的异常
            // 在这里,我们尝试下载远程文件到本地

            // 1. 创建HTTP通讯用连接对象HttpWebRequest对象
            HttpWebRequest httpWebRequest = HttpWebRequest.Create(new Uri("http://192.168.1.101:8000/HTTPRoot/pic.png")) as HttpWebRequest;

            // 2. 设置请求类型或其他相关参数
            httpWebRequest.Method = WebRequestMethods.Http.Get; // 使用HTTP GET请求方法
            httpWebRequest.Timeout = 3000; // 设置请求超时时间为3秒

            // 3. 发送请求,获取响应结果HttpWebResponse对象
            HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

            // 4. 获取响应数据流,写入本地路径
            if (httpWebResponse.StatusCode == HttpStatusCode.OK)
            {
                // 打印本地数据存储路径
                print("本地存储路径:" + Application.persistentDataPath);

                // 创建本地文件流以将下载的数据写入本地
                using (FileStream fileStream = File.Create(Application.persistentDataPath + "/httpPic.png"))
                {
                    Stream downloadResponseStream = httpWebResponse.GetResponseStream();
                    byte[] bytes = new byte[2048];

                    // 读取数据
                    int contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);

                    // 一点一点地写入本地
                    while (contentLength != 0)
                    {
                        fileStream.Write(bytes, 0, contentLength);
                        contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);
                    }

                    fileStream.Close();
                    downloadResponseStream.Close();
                    httpWebResponse.Close();
                }
                // 打印下载成功消息
                print("下载成功");
            }
            else
            {
                // 如果状态码不是200 (OK),下载失败,打印状态码
                print("下载失败,状态码:" + httpWebResponse.StatusCode);
            }
        }
        catch (WebException w)
        {
            // 捕获WebException异常,通常表示网络请求出错
            print("下载出错,状态:" + w.Status + ",错误消息:" + w.Message);
        }


        #endregion

        #region 知识点三 Get请求类型携带额外信息

        //我们在进行HTTP通信时,可以在地址后面加一些额外参数传递给服务端
        //一般在和短连接游戏服务器通讯时,需要携带额外信息

        //举例:
        //http://www.aspxfans.com:8080/news/child/index.asp?boardID=5&ID=24618&page=1
        //这个链接可以分成几部分

        //1.协议部分:取决于服务器端使用的哪种协议
        //http://  —— 普通的http超文本传输协议
        //https:// —— 加密的超文本传输协议

        //2.域名部分:
        //www.aspxfans.com
        //也可以填写服务器的公网IP地址

        //3.端口部分:
        //8080
        //可以不写,如果不写默认为80

        //4.虚拟目录部分:
        //news/child/
        //域名后的/开始,到最后一个/之前的部分

        //5.文件名部分:
        //index.asp
        //?之前的最后一个/后的部分

        //6.参数部分:
        //boardID=5&ID=24618&page=1
        //?之后的部分就是参数部分,多个参数一&分隔开
        //这里有三个参数
        //boardID = 5
        //ID = 24618
        //page = 1

        //我们在和服务端进行通信时,只要按照这种规则格式进行通信,就可以传递参数给对象
        //主要可用于:
        //1.web网站服务器
        //2.游戏短连接服务器
        //等

        #endregion

        #region 总结

        //1.Head请求类型
        //主要用于获取文件的一些基础信息 可以用于确定文件是否存在

        //2.Get请求类型 主要用于传递信息给服务器,用于获取具体信息
        //  服务器返回的信息,可以通过Response中的流来获取
        //  用Get请求时,可以在连接中携带一些额外参数(在链接后面加上 ?参数名=参数值&参数名=参数值&参数名=参数值&。。。。)
        //  正常的http服务器应用程序,都会去解析Get请求时连接中的参数进行逻辑处理(后端程序的工作)
        //  我们主要要掌握的知识点:
        //  1.额外参数按格式书写
        //  2.通过response对象中的流来获取返回的数据(数据的类型多种多样,可以是文件、自定义消息等等,我们按照规则解析即可)

        //3.在和http服务器通信时,我们经常会使用额外参数的形式传递信息,特别是以后和一些运营平台对接时

        //4.文件下载功能和Ftp非常类似,只是其中使用的类、协议、请求类型不同而已

        #endregion
    }
}

49.3 练习题

实现一个Http管理器,将下载方法封装在其中,用多线程的形式处理下载,避免影响主线程逻辑

创建HttpManager管理器,继承C#单例,定义服务器路径

public class HttpManager : BaseSingletonInCSharp<HttpManager>
{
    private string HTTP_PATH = "http://192.168.1.101:8000/HTTPRoot/";
}

定义下载指定文件到本地指定路径中的方法,先用Head判断文件是否存在,存在在用Get获取

/// <summary>
/// 下载指定文件到本地指定路径中
/// </summary>
/// <param name="fileName">远程文件名</param>
/// <param name="loacFilePath">本地路径</param>
/// <param name="action">下载结束后的回调函数</param>
public async void DownLoadFile(string fileName, string loacFilePath, UnityAction<HttpStatusCode> action)
{
    // 创建一个临时变量,用于存储HTTP响应的状态码,默认为OK。
    HttpStatusCode httpStatusCodeResult = HttpStatusCode.OK;

    // 使用异步任务来执行下载操作,以避免阻塞主线程。
    await Task.Run(() =>
    {
        try
        {
            // 判断文件是否存在 Head 

            // 1. 创建HTTP连接对象,用于发送HTTP请求到服务器。
            HttpWebRequest httpWebRequest = HttpWebRequest.Create(HTTP_PATH + fileName) as HttpWebRequest;

            // 2. 设置请求类型为HEAD,这样我们可以检查文件是否存在,以及设置其他相关参数。
            httpWebRequest.Method = WebRequestMethods.Http.Head;
            httpWebRequest.Timeout = 2000;

            // 3. 发送请求并获取HTTP响应。
            HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

            // 如果文件存在才下载
            if (httpWebResponse.StatusCode == HttpStatusCode.OK)
            {
                // 关闭判断文件是否存在的请求。
                httpWebResponse.Close();

                // 下载文件 Get 

                // 1. 创建新的HTTP连接对象,用于下载文件。
                httpWebRequest = HttpWebRequest.Create(HTTP_PATH + fileName) as HttpWebRequest;

                // 2. 设置请求类型为GET,以获取文件内容,并设置其他相关参数。
                httpWebRequest.Method = WebRequestMethods.Http.Get;
                httpWebRequest.Timeout = 2000;

                // 3. 发送请求并获取HTTP响应。
                httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

                // 4. 存储数据到本地
                if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                {
                    // 创建本地文件并准备将下载的数据写入其中。
                    using (FileStream fileStream = File.Create(loacFilePath))
                    {
                        // 获取HTTP响应的数据流,从中读取数据。
                        Stream downloadResponseStream = httpWebResponse.GetResponseStream();

                        // 创建一个字节数组,用于存储从数据流中读取的数据。
                        byte[] bytes = new byte[4096];
                        // 从数据流中读取一部分数据,并返回读取的字节数。
                        int contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);

                        // 使用循环将数据写入本地文件,直到数据流读取完毕。
                        while (contentLength != 0)
                        {
                            fileStream.Write(bytes, 0, contentLength);
                            contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);
                        }

                        // 关闭本地文件和数据流。
                        fileStream.Close();
                        downloadResponseStream.Close();
                    }
                    // 如果下载成功,将HTTP响应状态码设置为OK。
                    httpStatusCodeResult = HttpStatusCode.OK;
                }
                else
                {
                    // 如果下载失败,将HTTP响应状态码存储在 httpStatusCodeResult 变量中。
                    httpStatusCodeResult = httpWebResponse.StatusCode;
                }

            }
            else
            {
                // 如果文件不存在,将HTTP响应状态码存储在 httpStatusCodeResult 变量中。
                httpStatusCodeResult = httpWebResponse.StatusCode;
            }

            // 关闭HTTP响应。
            httpWebResponse.Close();
        }
        catch (WebException w)
        {
            // 如果发生Web异常,将状态码设置为服务器内部错误,并记录错误消息。
            httpStatusCodeResult = HttpStatusCode.InternalServerError;
            Debug.Log("下载出错" + w.Message + w.Status);
        }
    });

    // 调用传递进来的 UnityAction 委托,将HTTP响应状态码传递给调用者。
    action?.Invoke(httpStatusCodeResult);
}

测试下载服务器图片

print(Application.persistentDataPath);

HttpManager.Instance.DownLoadFile("pic.png", Application.persistentDataPath + "/httppic2.png", (code) =>
{
    if (code == HttpStatusCode.OK)
        print("下载成功");
    else
        print("下载失败" + code);
});

测试结果


49.4 练习题代码

HttpManager

using System.IO;
using System.Net;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

public class HttpManager : BaseSingletonInCSharp<HttpManager>
{
    private string HTTP_PATH = "http://192.168.1.101:8000/HTTPRoot/";

    /// <summary>
    /// 下载指定文件到本地指定路径中
    /// </summary>
    /// <param name="fileName">远程文件名</param>
    /// <param name="loacFilePath">本地路径</param>
    /// <param name="action">下载结束后的回调函数</param>
    public async void DownLoadFile(string fileName, string loacFilePath, UnityAction<HttpStatusCode> action)
    {
        // 创建一个临时变量,用于存储HTTP响应的状态码,默认为OK。
        HttpStatusCode httpStatusCodeResult = HttpStatusCode.OK;

        // 使用异步任务来执行下载操作,以避免阻塞主线程。
        await Task.Run(() =>
        {
            try
            {
                // 判断文件是否存在 Head 

                // 1. 创建HTTP连接对象,用于发送HTTP请求到服务器。
                HttpWebRequest httpWebRequest = HttpWebRequest.Create(HTTP_PATH + fileName) as HttpWebRequest;

                // 2. 设置请求类型为HEAD,这样我们可以检查文件是否存在,以及设置其他相关参数。
                httpWebRequest.Method = WebRequestMethods.Http.Head;
                httpWebRequest.Timeout = 2000;

                // 3. 发送请求并获取HTTP响应。
                HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

                // 如果文件存在才下载
                if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                {
                    // 关闭判断文件是否存在的请求。
                    httpWebResponse.Close();

                    // 下载文件 Get 

                    // 1. 创建新的HTTP连接对象,用于下载文件。
                    httpWebRequest = HttpWebRequest.Create(HTTP_PATH + fileName) as HttpWebRequest;

                    // 2. 设置请求类型为GET,以获取文件内容,并设置其他相关参数。
                    httpWebRequest.Method = WebRequestMethods.Http.Get;
                    httpWebRequest.Timeout = 2000;

                    // 3. 发送请求并获取HTTP响应。
                    httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;

                    // 4. 存储数据到本地
                    if (httpWebResponse.StatusCode == HttpStatusCode.OK)
                    {
                        // 创建本地文件并准备将下载的数据写入其中。
                        using (FileStream fileStream = File.Create(loacFilePath))
                        {
                            // 获取HTTP响应的数据流,从中读取数据。
                            Stream downloadResponseStream = httpWebResponse.GetResponseStream();

                            // 创建一个字节数组,用于存储从数据流中读取的数据。
                            byte[] bytes = new byte[4096];
                            // 从数据流中读取一部分数据,并返回读取的字节数。
                            int contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);

                            // 使用循环将数据写入本地文件,直到数据流读取完毕。
                            while (contentLength != 0)
                            {
                                fileStream.Write(bytes, 0, contentLength);
                                contentLength = downloadResponseStream.Read(bytes, 0, bytes.Length);
                            }

                            // 关闭本地文件和数据流。
                            fileStream.Close();
                            downloadResponseStream.Close();
                        }
                        // 如果下载成功,将HTTP响应状态码设置为OK。
                        httpStatusCodeResult = HttpStatusCode.OK;
                    }
                    else
                    {
                        // 如果下载失败,将HTTP响应状态码存储在 httpStatusCodeResult 变量中。
                        httpStatusCodeResult = httpWebResponse.StatusCode;
                    }

                }
                else
                {
                    // 如果文件不存在,将HTTP响应状态码存储在 httpStatusCodeResult 变量中。
                    httpStatusCodeResult = httpWebResponse.StatusCode;
                }

                // 关闭HTTP响应。
                httpWebResponse.Close();
            }
            catch (WebException w)
            {
                // 如果发生Web异常,将状态码设置为服务器内部错误,并记录错误消息。
                httpStatusCodeResult = HttpStatusCode.InternalServerError;
                Debug.Log("下载出错" + w.Message + w.Status);
            }
        });

        // 调用传递进来的 UnityAction 委托,将HTTP响应状态码传递给调用者。
        action?.Invoke(httpStatusCodeResult);
    }

}

Lesson49_练习题

using System.Collections;
using System.Collections.Generic;
using System.Net;
using UnityEngine;

public class Lesson49_练习题 : MonoBehaviour
{
    void Start()
    {
        print(Application.persistentDataPath);

        HttpManager.Instance.DownLoadFile("pic.png", Application.persistentDataPath + "/httppic2.png", (code) =>
        {
            if (code == HttpStatusCode.OK)
                print("下载成功");
            else
                print("下载失败" + code);
        });
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏