55.UnityWebReq类常用上传数据

55.网络通信-Unity网络类-UnityWebRequest类-常用上传数据


55.1 知识点

上传相关数据类

父接口IMultipartFormSection 数据相关类都继承该接口

//数据相关类都继承该接口
//我们可以用父类装子类
List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();

子类MultipartFormDataSection 传键值对

//MultipartFormDataSection 一般用来传键值对
//1.二进制字节数组
multipartFormSectionList.Add(new MultipartFormDataSection(Encoding.UTF8.GetBytes("123123123123123")));
//2.字符串
multipartFormSectionList.Add(new MultipartFormDataSection("12312312312312312dsfasdf"));
//3.参数名,参数值(字节数组,字符串),编码类型,资源类型(常用)
multipartFormSectionList.Add(new MultipartFormDataSection("Name", "MrTao", Encoding.UTF8, "application/...."));
//4.参数名,字节数组,资源类型
multipartFormSectionList.Add(new MultipartFormDataSection("Msg", new byte[1024], "appl....."));

子类MultipartFormFileSection 传文件

//MultipartFormFileSection 一般用来传文件
//1.字节数组
multipartFormSectionList.Add(new MultipartFormFileSection(File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));
//2.文件名,字节数组(常用)
multipartFormSectionList.Add(new MultipartFormFileSection("上传的文件.png", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));
//3.字符串数据,文件名(常用)
multipartFormSectionList.Add(new MultipartFormFileSection("12312313212312", "test.txt"));
//4.字符串数据,编码格式,文件名(常用)
multipartFormSectionList.Add(new MultipartFormFileSection("12312313212312", Encoding.UTF8, "test.txt"));
//5.表单名,字节数组,文件名,文件类型
multipartFormSectionList.Add(new MultipartFormFileSection("file", new byte[1024], "test.txt", ""));
//6.表单名,字符串数据,编码格式,文件名
multipartFormSectionList.Add(new MultipartFormFileSection("file", "123123123", Encoding.UTF8, "test.txt"));

UnityWebRequest.Post上传相关

// 用于协同处理Post上传操作
IEnumerator UploadPost()
{
    // 准备上传的数据的列表
    List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();

    // 添加键值对相关的信息字段数据
    // 添加名为 "Name" 的文本字段,值为 "MrTao"
    multipartFormSectionList.Add(new MultipartFormDataSection("Name", "MrTao"));

    // 创建一个 PlayerMessage 对象
    PlayerMessage playerMessage = new PlayerMessage();
    playerMessage.playerID = 1;
    playerMessage.playerData = new PlayerData();
    playerMessage.playerData.name = "MrTao";
    playerMessage.playerData.atk = 6;
    playerMessage.playerData.lev = 666;
    // 添加名为 "playerMessage" 的文本字段,值为 PlayerMessage 对象的 JSON 字符串表示
    multipartFormSectionList.Add(new MultipartFormDataSection("playerMessage", playerMessage.Writing()));

    // 添加一些文件上传部分

    // 添加名为 "TestTest123.png" 的二进制文件,内容为从指定路径读取的二进制数据
    multipartFormSectionList.Add(new MultipartFormFileSection("TestTest123.png", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));

    // 添加名为 "123123123123123" 的文本文件,内容为 "Test123.txt" 文件的内容
    multipartFormSectionList.Add(new MultipartFormFileSection("123123123123123", "Test123.txt"));

    // 创建 UnityWebRequest 对象,将数据上传到指定的URL
    UnityWebRequest unityWebRequest = UnityWebRequest.Post("http://192.168.1.101:8000/HTTPRoot/", multipartFormSectionList);

    // 发送上传请求
    unityWebRequest.SendWebRequest();

    // 等待上传完成
    while (!unityWebRequest.isDone)
    {
        // 打印上传进度和已上传的字节数
        print(unityWebRequest.uploadProgress);
        print(unityWebRequest.uploadedBytes);
        yield return null;
    }

    // 打印最终上传进度和已上传的字节数
    print(unityWebRequest.uploadProgress);
    print(unityWebRequest.uploadedBytes);

    // 检查上传是否成功
    if (unityWebRequest.result == UnityWebRequest.Result.Success)
    {
        print("上传成功");
        // 上传成功后,可以使用 unityWebRequest.downloadHandler.multipartFormSectionList 获取上传数据列表
    }
    else
    {
        // 上传失败时,打印错误信息、响应代码和结果
        print("上传失败" + unityWebRequest.error + unityWebRequest.responseCode + unityWebRequest.result);
    }
}


StartCoroutine(UploadPost());

UnityWebRequest.Put上传相关

// 用于协同处理Put上传操作
IEnumerator UploadPut()
{
    // 创建 UnityWebRequest 对象,使用 HTTP PUT 方法上传文件

    // 指定要上传的URL和要上传的文件内容,这里使用了 UnityWebRequest.Put 方法 要后端配合
    UnityWebRequest unityWebRequest = UnityWebRequest.Put("http://192.168.1.101:8000/HTTPRoot/", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png"));

    // 发送上传请求并等待完成
    yield return unityWebRequest.SendWebRequest();

    // 检查上传是否成功
    if (unityWebRequest.result == UnityWebRequest.Result.Success)
    {
        print("Put 上传成功");
    }
    else
    {
        // 在上传失败时可以添加错误处理逻辑
        // 例如,可以通过 unityWebRequest.error 访问错误消息,以便进行错误处理
    }
}


// 注意:Put请求类型不是所有的web服务器都认,必须要服务器处理该请求类型那么才能有相应
StartCoroutine(UploadPut());

总结

我们可以利用Post上传数据或上传文件
Put主要用于上传文件,但是必须资源服务器支持Put请求类型
为了通用性,我们可以统一使用Post请求类型进行数据和资源的上传
它的使用和之前的WWW类似,只要前后端制定好规则就可以相互通信了


55.2 知识点代码

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

public class Lesson55_网络通信_Unity网络类_UnityWebRequest类_常用上传数据 : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 上传相关数据类

        //数据父接口 IMultipartFormSection
        //数据相关类都继承该接口
        //我们可以用父类装子类
        List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();


        //数据子类

        //MultipartFormDataSection 一般用来传键值对
        //1.二进制字节数组
        multipartFormSectionList.Add(new MultipartFormDataSection(Encoding.UTF8.GetBytes("123123123123123")));
        //2.字符串
        multipartFormSectionList.Add(new MultipartFormDataSection("12312312312312312dsfasdf"));
        //3.参数名,参数值(字节数组,字符串),编码类型,资源类型(常用)
        multipartFormSectionList.Add(new MultipartFormDataSection("Name", "MrTao", Encoding.UTF8, "application/...."));
        //4.参数名,字节数组,资源类型
        multipartFormSectionList.Add(new MultipartFormDataSection("Msg", new byte[1024], "appl....."));

        //MultipartFormFileSection 一般用来传文件
        //1.字节数组
        multipartFormSectionList.Add(new MultipartFormFileSection(File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));
        //2.文件名,字节数组(常用)
        multipartFormSectionList.Add(new MultipartFormFileSection("上传的文件.png", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));
        //3.字符串数据,文件名(常用)
        multipartFormSectionList.Add(new MultipartFormFileSection("12312313212312", "test.txt"));
        //4.字符串数据,编码格式,文件名(常用)
        multipartFormSectionList.Add(new MultipartFormFileSection("12312313212312", Encoding.UTF8, "test.txt"));
        //5.表单名,字节数组,文件名,文件类型
        multipartFormSectionList.Add(new MultipartFormFileSection("file", new byte[1024], "test.txt", ""));
        //6.表单名,字符串数据,编码格式,文件名
        multipartFormSectionList.Add(new MultipartFormFileSection("file", "123123123", Encoding.UTF8, "test.txt"));

        #endregion

        #region 知识点二 Post发送相关

        StartCoroutine(UploadPost());

        #endregion

        #region 知识点三 Put上传相关

        //注意:Put请求类型不是所有的web服务器都认,必须要服务器处理该请求类型那么才能有相应
        StartCoroutine(UploadPut());

        #endregion

        #region 总结

        //我们可以利用Post上传数据或上传文件
        //Put主要用于上传文件,但是必须资源服务器支持Put请求类型
        //为了通用性,我们可以统一使用Post请求类型进行数据和资源的上传
        //它的使用和之前的WWW类似,只要前后端制定好规则就可以相互通信了

        #endregion
    }

    #region 知识点二 Post发送相关

    // 用于协同处理Post上传操作
    IEnumerator UploadPost()
    {
        // 准备上传的数据的列表
        List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();

        // 添加键值对相关的信息字段数据
        // 添加名为 "Name" 的文本字段,值为 "MrTao"
        multipartFormSectionList.Add(new MultipartFormDataSection("Name", "MrTao"));
        // 创建一个 PlayerMessage 对象
        PlayerMessage playerMessage = new PlayerMessage();
        playerMessage.playerID = 1;
        playerMessage.playerData = new PlayerData();
        playerMessage.playerData.name = "MrTao";
        playerMessage.playerData.atk = 6;
        playerMessage.playerData.lev = 666;
        // 添加名为 "playerMessage" 的文本字段,值为 PlayerMessage 对象的 JSON 字符串表示
        multipartFormSectionList.Add(new MultipartFormDataSection("playerMessage", playerMessage.Writing()));

        // 添加一些文件上传部分
        // 添加名为 "TestTest123.png" 的二进制文件,内容为从指定路径读取的二进制数据
        multipartFormSectionList.Add(new MultipartFormFileSection("TestTest123.png", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png")));
        // 添加名为 "123123123123123" 的文本文件,内容为 "Test123.txt" 文件的内容
        multipartFormSectionList.Add(new MultipartFormFileSection("123123123123123", "Test123.txt"));

        // 创建 UnityWebRequest 对象,将数据上传到指定的URL
        UnityWebRequest unityWebRequest = UnityWebRequest.Post("http://192.168.1.101:8000/HTTPRoot/", multipartFormSectionList);

        // 发送上传请求
        unityWebRequest.SendWebRequest();

        // 等待上传完成
        while (!unityWebRequest.isDone)
        {
            // 打印上传进度和已上传的字节数
            print(unityWebRequest.uploadProgress);
            print(unityWebRequest.uploadedBytes);
            yield return null;
        }

        // 打印最终上传进度和已上传的字节数
        print(unityWebRequest.uploadProgress);
        print(unityWebRequest.uploadedBytes);

        // 检查上传是否成功
        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
            print("上传成功");
            // 上传成功后,可以使用 unityWebRequest.downloadHandler.multipartFormSectionList 获取上传数据列表
        }
        else
        {
            // 上传失败时,打印错误信息、响应代码和结果
            print("上传失败" + unityWebRequest.error + unityWebRequest.responseCode + unityWebRequest.result);
        }
    }

    #endregion

    #region 知识点三 Put上传相关

    // 用于协同处理Put上传操作
    IEnumerator UploadPut()
    {
        // 创建 UnityWebRequest 对象,使用 HTTP PUT 方法上传文件

        // 指定要上传的URL和要上传的文件内容,这里使用了 UnityWebRequest.Put 方法 要后端配合
        UnityWebRequest unityWebRequest = UnityWebRequest.Put("http://192.168.1.101:8000/HTTPRoot/", File.ReadAllBytes(Application.streamingAssetsPath + "/test.png"));

        // 发送上传请求并等待完成
        yield return unityWebRequest.SendWebRequest();

        // 检查上传是否成功
        if (unityWebRequest.result == UnityWebRequest.Result.Success)
        {
            print("Put 上传成功");
        }
        else
        {
            // 在上传失败时可以添加错误处理逻辑
            // 例如,可以通过 unityWebRequest.error 访问错误消息,以便进行错误处理
        }
    }

    #endregion
}

55.3 练习题

请在一个NetWWW管理类当中,封装一个基于UnityWebRequest上传文件的方法

在NetWWW管理器中封装异步用UnityWebRequest上传的方法

/// <summary>
/// 上传文件的方法
/// </summary>
/// <param name="fileName">上传上去的文件名</param>
/// <param name="localPath">本地想要上传文件的路径</param>
/// <param name="action">上传完成后的回调函数</param>
public void UploadFile(string fileName, string localPath, UnityAction<UnityWebRequest.Result> action)
{
    StartCoroutine(UploadFileAsync(fileName, localPath, action));
}

/// <summary>
/// 异步上传文件的方法
/// </summary>
/// <param name="fileName">上传上去的文件名</param>
/// <param name="localPath">本地想要上传文件的路径</param>
/// <param name="action">上传完成后的回调函数</param>
/// <returns></returns>
private IEnumerator UploadFileAsync(string fileName, string localPath, UnityAction<UnityWebRequest.Result> action)
{
    // 创建一个列表来存储上传文件的数据
    List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();
    // 向列表中添加要上传的文件,包括文件名和文件的二进制数据
    multipartFormSectionList.Add(new MultipartFormFileSection(fileName, File.ReadAllBytes(localPath)));

    // 创建一个UnityWebRequest对象,用于执行文件上传
    UnityWebRequest unityWebRequest = UnityWebRequest.Post(HTTP_SERVER_PATH, multipartFormSectionList);

    // 发送上传请求并等待完成
    yield return unityWebRequest.SendWebRequest();

    // 调用回调函数,传递上传结果
    action?.Invoke(unityWebRequest.result);

    // 如果上传不成功
    if (unityWebRequest.result != UnityWebRequest.Result.Success)
    {
        // 输出警告信息,包括错误消息和响应代码
        Debug.LogWarning("上传出现问题" + unityWebRequest.error + unityWebRequest.responseCode);
    }
}

进行测试

NetWWWManager.Instance.UploadFile("练习题上传UnityWebRequest.png", Application.streamingAssetsPath + "/test.png", (code) =>
{
    if (code == UnityWebRequest.Result.Success)
    {
        print("上传成功");
    }
    else
        print("上传失败" + code);
});

55.4 练习题代码

NetWWWManager

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;

public class NetWWWManager : BaseSingletonInMonoBehaviour<NetWWWManager>
{
    private string HTTP_SERVER_PATH = "http://192.168.1.101:8000/HTTPRoot/";


    /// <summary>
    /// 提供给外部加载资源用的方法
    /// </summary>
    /// <typeparam name="T">资源的类型</typeparam>
    /// <param name="path">资源的路径 http ftp file都支持</param>
    /// <param name="action">加载结束后的回调函数 因为WWW是通过结合协同程序异步加载的 所以不能马上获取结果 需要回调获取</param>
    public void LoadResource<T>(string path, UnityAction<T> action) where T : class
    {
        StartCoroutine(LoadResourceAsync<T>(path, action));
    }


    /// <summary>
    /// 内部异步使用WWW加载资源用的协程方法
    /// </summary>
    /// <typeparam name="T">资源的类型</typeparam>
    /// <param name="path">资源的路径 http ftp file都支持</param>
    /// <param name="action">加载结束后的回调函数 因为WWW是通过结合协同程序异步加载的 所以不能马上获取结果 需要回调获取</param>
    private IEnumerator LoadResourceAsync<T>(string path, UnityAction<T> action) where T : class
    {
        //声明www对象 用于下载或加载
        WWW www = new WWW(path);

        //等待下载或者加载结束(异步)
        yield return www;

        //优化的话可以让外部多传一个在加载时逻辑处理的委托回调

        //如果没有错误 证明加载成功
        if (www.error == null)
        {
            //根据T泛型的类型  决定使用哪种类型的资源 传递给外部
            if (typeof(T) == typeof(AssetBundle))
            {
                action?.Invoke(www.assetBundle as T);
            }
            else if (typeof(T) == typeof(Texture))
            {
                action?.Invoke(www.texture as T);
            }
            else if (typeof(T) == typeof(AudioClip))
            {
                action?.Invoke(www.GetAudioClip() as T);
            }
            else if (typeof(T) == typeof(string))
            {
                action?.Invoke(www.text as T);
            }
            else if (typeof(T) == typeof(byte[]))
            {
                action?.Invoke(www.bytes as T);
            }
            //自定义一些类型 可能需要将bytes 转换成对应的类型来使用
        }
        //如果错误 就提示别人
        else
        {
            //优化的话可以让外部多传一个在错误时委托回调
            Debug.LogError("www加载资源出错" + www.error);
        }

    }



    /// <summary>
    /// 发送消息的通用方法,通过协程异步发送消息并在接收响应后执行指定的动作。
    /// </summary>
    /// <typeparam name="T">消息类型的泛型参数,必须是BaseMsg的派生类。</typeparam>
    /// <param name="baseMessage">要发送的消息对象。</param>
    /// <param name="action">消息发送成功后要执行的动作。</param>
    public void SendMessage<T>(BaseMessage baseMessage, UnityAction<T> action) where T : BaseMessage
    {
        // 启动协程异步发送消息
        StartCoroutine(SendMessageAsync<T>(baseMessage, action));
    }

    /// <summary>
    /// 通过协程异步发送消息,并等待响应。
    /// </summary>
    /// <typeparam name="T">消息类型的泛型参数,必须是BaseMsg的派生类。</typeparam>
    /// <param name="BaseMessage">要发送的消息对象。</param>
    /// <param name="action">消息发送成功后要执行的动作。</param>
    private IEnumerator SendMessageAsync<T>(BaseMessage BaseMessage, UnityAction<T> action) where T : BaseMessage
    {
        // 创建一个WWWForm来准备要发送的消息数据
        WWWForm wWWForm = new WWWForm();

        // 将消息数据以二进制形式添加到WWWForm中
        wWWForm.AddBinaryData("BaseMessage", BaseMessage.Writing());

        // 创建一个WWW对象并发送消息到HTTP服务器
        WWW www = new WWW(HTTP_SERVER_PATH, wWWForm);

        // 等待异步操作完成,即等待消息发送结束
        yield return www;

        // 检查是否有错误发生
        if (www.error == null)
        {
            // 解析从服务器返回的消息,提取消息ID和消息长度
            int index = 0;
            int msgID = BitConverter.ToInt32(www.bytes, index);
            index += 4;
            int msgLength = BitConverter.ToInt32(www.bytes, index);
            index += 4;

            // 根据消息ID反序列化消息
            BaseMessage baseMessage = null;
            switch (msgID)
            {
                case 1001:
                    baseMessage = new PlayerMessage();
                    baseMessage.Reading(www.bytes, index);
                    break;
            }

            // 调用指定的动作,并将反序列化后的消息作为泛型参数传递
            if (baseMessage != null)
                action?.Invoke(baseMessage as T);
        }
        else
        {
            // 输出错误信息
            Debug.LogError("发消息出问题" + www.error);
        }
    }


    /// <summary>
    /// 上传文件的方法
    /// </summary>
    /// <param name="fileName">上传上去的文件名</param>
    /// <param name="localPath">本地想要上传文件的路径</param>
    /// <param name="action">上传完成后的回调函数</param>
    public void UploadFile(string fileName, string localPath, UnityAction<UnityWebRequest.Result> action)
    {
        StartCoroutine(UploadFileAsync(fileName, localPath, action));
    }

    /// <summary>
    /// 异步上传文件的方法
    /// </summary>
    /// <param name="fileName">上传上去的文件名</param>
    /// <param name="localPath">本地想要上传文件的路径</param>
    /// <param name="action">上传完成后的回调函数</param>
    /// <returns></returns>
    private IEnumerator UploadFileAsync(string fileName, string localPath, UnityAction<UnityWebRequest.Result> action)
    {
        // 创建一个列表来存储上传文件的数据
        List<IMultipartFormSection> multipartFormSectionList = new List<IMultipartFormSection>();
        // 向列表中添加要上传的文件,包括文件名和文件的二进制数据
        multipartFormSectionList.Add(new MultipartFormFileSection(fileName, File.ReadAllBytes(localPath)));

        // 创建一个UnityWebRequest对象,用于执行文件上传
        UnityWebRequest unityWebRequest = UnityWebRequest.Post(HTTP_SERVER_PATH, multipartFormSectionList);

        // 发送上传请求并等待完成
        yield return unityWebRequest.SendWebRequest();

        // 调用回调函数,传递上传结果
        action?.Invoke(unityWebRequest.result);

        // 如果上传不成功
        if (unityWebRequest.result != UnityWebRequest.Result.Success)
        {
            // 输出警告信息,包括错误消息和响应代码
            Debug.LogWarning("上传出现问题" + unityWebRequest.error + unityWebRequest.responseCode);
        }
    }

}

Lesson55_练习题

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class Lesson55_练习题 : MonoBehaviour
{
    void Start()
    {
        NetWWWManager.Instance.UploadFile("练习题上传UnityWebRequest.png", Application.streamingAssetsPath + "/test.png", (code) =>
        {
            if (code == UnityWebRequest.Result.Success)
            {
                print("上传成功");
            }
            else
                print("上传失败" + code);
        });
    }
}


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

×

喜欢就点赞,疼爱就打赏