Unity框架最佳实践

Unity是实时3D互动内容创作和运营平台。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助Unity将创意变成现实。Unity平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。

1. 背景说明

随着使用Unity开发的移动应用越来越多,应用类型越来越广泛,我们专门提供了针对UnityHTTPDNS插件,方便Unity开发者以熟悉方式接入HTTPDNS功能。

2. Demo示例

环境说明

Unity 2022.3.62f1c1

项目说明

项目地址:下载地址

本项目是一个unity demo项目,Assets/Plugins目录下为插件代码。

集成操作

复制Assets/Pluginsunity项目

目前插件直接以文件的方式提供,后续再考虑封装为Unity Package。

重要

插件使用了baseProjectTemplate, mainTemplate, proguard-user, settingsTemplate等文件,如果项目有其他地方也需要定制这些文件,请注意合并修改内容。

3. 接入示例

配置

在使用 HTTPDNS 之前,需要先初始化服务并进行相关配置:

using UnityEngine;
using Aliyun.HttpDns;
using System.Collections.Generic;

public class HttpDnsManager : MonoBehaviour 
{
    void Start()
    {
        // 1. 初始化服务:传入您的 Account ID 和 Secret Key (如果开启了鉴权)
        HttpDnsHelper.init("accountId", "secret");

        // 2. 功能配置:根据需求开启或关闭功能
        HttpDnsHelper.debug(true);                      // 开启调试日志,方便开发阶段排查问题
        HttpDnsHelper.setHttpsRequestEnabled(true);     // 使用 HTTPS 请求解析,增强安全性
        HttpDnsHelper.setTimeout(3000);                 // 设置请求超时时间(毫秒)

        // 3. 高级功能配置:优化性能和连接成功率
        HttpDnsHelper.setReuseExpiredIPEnabled(true);         // 允许在网络请求失败时,复用已过期的IP进行重试
        HttpDnsHelper.setPersistentCacheIPEnabled(true);      // 启用IP持久化缓存,将解析结果缓存到本地
        HttpDnsHelper.setPreResolveAfterNetworkChanged(true); // 开启网络变化时自动预解析,提升后续解析速度

        // 4. 预解析:提前解析一些常用域名
        var hostsToPreResolve = new List<string> { "www.taobao.com", "www.aliyun.com" };
        HttpDnsHelper.setPreResolveHosts(hostsToPreResolve, "auto");

        // 5. 构建并启动服务:应用所有配置
        bool success = HttpDnsHelper.build();
        if (success) 
        {
            Debug.Log("HTTPDNS 服务初始化成功!");
        }
        else 
        {
            Debug.LogError("HTTPDNS 服务初始化失败,将回退到系统DNS。");
        }
    }
}

使用

用解析得到的ip发送网络请求:

using System;
using System.Net.Http;
using System.Threading.Tasks;
using UnityEngine;

public class NetworkRequestExample
{
    private static readonly HttpClient httpClient = new HttpClient();

    public async Task MakeRequest(string url)
    {
        var uri = new Uri(url);
        string originalHost = uri.Host;
        string resolvedIP = null;

        // 1. 使用 HTTPDNS 解析域名
        var ips = HttpDnsHelper.getIpsByHostAsync(originalHost);
        if (ips != null && ips.Count > 0)
        {
            resolvedIP = ips[0]; // 使用第一个 IP
        }

        // 如果解析成功,则使用 IP 发起请求
        if (!string.IsNullOrEmpty(resolvedIP))
        {
            // 2. 构建新的 URL
            string newUrl = url.Replace(originalHost, resolvedIP);

            try
            {
                using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, newUrl))
                {
                    // 3. 关键步骤:设置 Host 请求头为原始域名,以确保 HTTPS/SNI 正确性
                    requestMessage.Headers.Host = originalHost;
                    
                    var response = await httpClient.SendAsync(requestMessage);
                    response.EnsureSuccessStatusCode();
                    
                    string result = await response.Content.ReadAsStringAsync();
                    Debug.Log("使用 HTTPDNS 请求成功!");
                }
            }
            catch (Exception e)
            {
                Debug.LogError($"使用 HTTPDNS 请求失败: {e.Message}");
                // 此处可添加回退逻辑,例如使用原始 URL 重新请求
            }
        }
        else
        {
            Debug.LogWarning($"HTTPDNS 未能解析 {originalHost},将使用系统 DNS 直接请求。");
            // 此处直接使用原始 URL 发起请求
        }
    }
}

4. 不同网络模块适配

当使用不同的网络模块发送请求时,需要相应地进行请求头配置等操作,下面对HttpClient、HttpWebRequest、UnityWebRequest三种类型分别给出示例:

HttpClient

private static readonly System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();

var uri = new System.Uri(url);
String ip = ResolveWithHttpDns(uri.Host);
string newUrl = url.Replace(uri.Host, ip);

try
{
    using (var requestMessage = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, newUrl))
    {
        // 关键步骤:设置Host头
        requestMessage.Headers.Host = uri.Host;
        var response = await httpClient.SendAsync(requestMessage);
        response.EnsureSuccessStatusCode();
        string result = await response.Content.ReadAsStringAsync();
    }
}
catch (Exception e)
{

}

HttpWebRequest

var uri = new System.Uri(url);
String ip = ResolveWithHttpDns(uri.Host);
string newUrl = url.Replace(uri.Host, ip);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(newUrl);
request.Method = "GET";
// 关键步骤:设置Host头
request.Host = uri.Host;

try
{
    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using (Stream stream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(stream))
    {
        string result = reader.ReadToEnd();
    }
}
catch (Exception e)
{

}

UnityWebRequest(不推荐)

重要

由于UnityWebRequest无法正确配置SNI(服务器域名指示)信息,当服务器依赖SNI返回特定域名证书时,会导致SSL验证失败。因此处理这类域名时,推荐使用前两种网络请求方式。

var uri = new System.Uri(url);
String ip = ResolveWithHttpDns(uri.Host);
string newUrl = url.Replace(uri.Host, ip);

using (UnityWebRequest request = UnityWebRequest.Get(newUrl))
{
    // 关键步骤:设置Host头
    request.SetRequestHeader("Host", uri.Host);
    var operation = request.SendWebRequest();
    while (!operation.isDone)
    {

    }

    if (request.result == UnityWebRequest.Result.Success)
    {
        string response = request.downloadHandler.text;
    }
}