本文档介绍了Unity场景下的接入移动解析HTTPDNS的方案。
一、概述
Unity是内容创作引擎。Unity可以开发:2D/3D游戏,2D/3D应用,VR,AR,甚至移动App,网页前端 ,电影实时渲染等,创作者可以借助Unity将创意变成现实。
为方便 Unity 开发者接入使用移动解析HTTPDNS SDK,我们提供了针对Unity场景下的PdnsUnityDemo源码供用户参考,源码中提供了移动解析HTTPDNS Unity插件。
PdnsUnityDemo使用的是Unity 2019.4.21f1c1开发版本,Assets/Plugins目录下为插件(用户也可根据实际情况使用阿里云DNS SDK来制作插件),插件使用了定制的Gradle文件和Proguard文件,如果您的项目有其他地方也定制了这些文件,将内容合并即可。
二、集成方式
导入Plugins文件。
将PdnsUnityDemo中 Plugins 文件夹中的文件复制到您 Unity 工程>Assets>Plugins 文件夹中。
配置参数。
AlipdnsHelper.setAccountIdAndSetAccessKeyIdAndSetAccesskeySecret("accountId","accessKeyId","accesskeySecret");
AlipdnsHelper.setCacheEnable(true);
AlipdnsHelper.setSchedulePrefetchEnable(true);
AlipdnsHelper.setIspEnable(true);
AlipdnsHelper.setMaxCacheTTL(3600);
AlipdnsHelper.setMaxNegativeCache(60);
AlipdnsHelper.setScheme(1);
AlipdnsHelper.setShortEnable(false);
AlipdnsHelper.setSpeedTestEnable(true);
AlipdnsHelper.setCacheCountLimit(100);
AlipdnsHelper.setSpeedPort(80);
// 预解析域名
List<string> list = new List<string>();
list.Add("域名1");
list.Add("域名2");
AlipdnsHelper.setPreloadDomains(list);三、API介绍
接口类为AlipdnsHelper.cs。
必传参数,accountId,您在控制台注册后,控制台会生成唯一标识Account ID。
必传参数,accessKeyId,accessKeySecret 在控制台开启鉴权后生成该参数,设置鉴权功能来保障用户身份安全,不被第三方未授权者盗用。
public static void setAccountIdAndSetAccessKeyIdAndSetAccesskeySecret(string accountId,string accessKeyId,string accessKeySecret)设置开启缓存,在第一次解析过域名后,后续再解析时, 优先获取缓存中的数据,可大大提高解析速度。
public static void setCacheEnable(bool enable)设置是否开启定时主动更新过期缓存,开启后SDK每分钟会自动更新过期缓存,保障用户缓存数据及时更新,但是可能会带来域名解析次数和客户端流量消耗的增多。
public static void setSchedulePrefetchEnable(bool enable)设置是否开启依据ISP网络区分域名缓存,开启后则在不同网络环境下域名缓存数据分别存储互不影响。如果不开启,则在不同网络下使用同一份域名缓存数据。
public static void setIspEnable(bool enable)设置缓存最大TTL时间,如果设置了该时间,则会限制缓存的最大TTL不超过该设置时间。
SDK默认该参数为3600s。
public static void setMaxCacheTTL(double maxCacheTTL)设置否定缓存最大TTL时间,设置了该时间,则会限制否定缓存的最大TTL不超过该设置时间。
SDK默认该参数为30s。
public static void setMaxNegativeCache(double maxNegativeCache)在访问DNS服务器进行解析时,是通过HTTP协议解析,还是通过HTTPS协议解析,可通过
scheme属性进行设置。scheme默认是0,使用HTTP协议进行解析,建议使用HTTP协议进行解析,解析速度更快,scheme设为1即使用HTTPS协议进行解析。
public static void setScheme(int scheme)设置是否开启short模式,移动解析HTTPDNS的DoH JSON API返回数据分为全量JSON和简要IP数组格式。SDK默认为全量JSON格式。
public static void setShortEnable(bool enable)设置是否开启IP优选,开启后解析结果数组会按照测速结果由快到慢的顺序排列。
public static void setSpeedTestEnable(bool enable)设置缓存数量,可以自定义缓存数量(支持范围100~500之间)。
public static void setCacheCountLimit(int cacheCountLimit)设置IP测速优选端口,设置socket探测指定端口。
public static void setSpeedPort(int speedPort)由于SDK自带缓存功能,在第一次解析完域名后,后续再次解析此域名可大大提高解析速度,所以建议在app启动后,可对app中可能要解析的域名进行预加载。
public static void setPreloadDomains(List<string> hosts)自动感知网络环境(ipv4-only、ipv6-only、ipv4和ipv6双栈)直接从缓存中获取适用于当前网络环境的IP数组,无需等待。如无缓存,或有缓存但已过期并且expiredIPEnabled为false,则返回空。
@param host 域名
@param expiredIPEnabled 是否允许返回过期ip
public static List<string> getIpsByCacheWithDomain(string host, bool expiredIPEnabled)直接从缓存中获取ipv4解析结果,无需等待. 如无缓存,或有缓存但已过期,并且expiredIPEnabled为false,则返回空。
@param host 域名
@param expiredIPEnabled 是否允许返回过期ip
public static List<string> getIpv4ByCacheWithDomain(string host, bool expiredIPEnabled)直接从缓存中获取ipv6解析结果,无需等待. 如无缓存,或有缓存但已过期,并且expiredIPEnabled为false,则返回空。
@param host 域名
@param expiredIPEnabled 是否允许返回过期ip
public static List<string> getIpv6ByCacheWithDomain(string host, bool expiredIPEnabled)获取请求移动解析HTTPDNS成功失败统计信息。
public static string getRequestReportInfo()四、最佳实践
4.1 原理说明
本示例展示了Unity中集成HTTPDNS的完整解决方案:
跨平台统一接口:使用
AlipdnsHelper提供统一的API接口平台特定实现:针对 iOS、Android、 SDK提供不同的底层实现
自动DNS替换:在网络请求前自动将域名替换为解析的IP地址
Host头设置:确保HTTPS/SSL连接的SNI正确性
4.2 网络请求集成
当使用不同的网络模块发送请求时,需要相应地进行请求头配置等操作,下面对HttpClient、HttpWebRequest、UnityWebRequest三种类型分别给出示例:
4.2.1 HttpClient
using System;
using System.Net.Http;
using UnityEngine;
public class AlipdnsHttpClient : MonoBehaviour
{
private static readonly HttpClient httpClient = new HttpClient();
public async void MakeRequest(string url)
{
try
{
var uri = new Uri(url);
string hostname = uri.Host;
// 使用HTTPDNS解析域名
var result = AlipdnsHelper.getIpsByCacheWithDomain(host, true);
if (result != null && result.Count > 0)
{
string resolvedIP = result[0];
string newUrl = url.Replace(hostname, resolvedIP);
using (var requestMessage = new HttpRequestMessage(HttpMethod.Get, newUrl))
{
// 关键:设置Host头保证SSL/SNI正确性
requestMessage.Headers.Host = hostname;
var response = await httpClient.SendAsync(requestMessage);
string content = await response.Content.ReadAsStringAsync();
Debug.Log($"请求成功: {response.StatusCode}");
}
}
}
catch (Exception e)
{
Debug.LogError($"请求失败: {e.Message}");
}
}
}4.2.2 HttpWebRequest
using System;
using System.IO;
using System.Net;
using UnityEngine;
public class AlipdnsWebRequest : MonoBehaviour
{
public void MakeRequest(string url)
{
try
{
var uri = new Uri(url);
string hostname = uri.Host;
// 使用HTTPDNS解析域名
var result = AlipdnsHelper.getIpsByCacheWithDomain(host, true);
if (result != null && result.Count > 0)
{
string resolvedIP = result[0];
string newUrl = url.Replace(hostname, resolvedIP);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(newUrl);
request.Method = "GET";
// 关键:设置Host头保证SSL/SNI正确性
request.Host = hostname;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
string content = reader.ReadToEnd();
Debug.Log($"请求成功: {response.StatusCode}");
}
}
}
catch (Exception e)
{
Debug.LogError($"请求失败: {e.Message}");
}
}
}4.2.3 UnityWebRequest(不推荐)
由于UnityWebRequest无法正确配置SNI(服务器域名指示)信息,当服务器依赖SNI返回特定域名证书时,会导致SSL验证失败。因此处理这类域名时,推荐使用前两种网络请求方式。
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class AlipdnsUnityWebRequest : MonoBehaviour
{
public IEnumerator MakeRequest(string url)
{
var uri = new Uri(url);
string hostname = uri.Host;
// 使用HTTPDNS解析域名
var result = AlipdnsHelper.getIpsByCacheWithDomain(host, true);
if (result != null && result.Count > 0)
{
string resolvedIP = result[0];
string newUrl = url.Replace(hostname, resolvedIP);
using (UnityWebRequest request = UnityWebRequest.Get(newUrl))
{
// 关键:设置Host头
request.SetRequestHeader("Host", hostname);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log($"请求成功: {request.responseCode}");
}
else
{
Debug.LogError($"请求失败: {request.error}");
}
}
}
}
}当前文档只针对Unity场景下移动解析HTTPDNS Android/iOS SDK的使用。
关于移动解析HTTPDNS Android/iOS SDK的接入与使用问题,请查看Android SDK开发指南、iOS SDK开发指南。
开发者在Unity场景下接入移动解析HTTPDNS Android/iOS SDK实践完整代码请参考PdnsUnityDemo源码。