本文檔介紹如何在 HarmonyOS 原生網路程式庫、RCP 和 webiew 中通過DoH,接入HTTPDNS。
1. 前言
在 HarmonyOS 平台,推薦您優先通過HarmonyOS SDK手冊。若您由於某些原因無法引入 SDK,您可以通過 DoH的接入,本文聚焦 HarmonyOS 下“網路程式庫或組件”的 DoH接入方式,涵蓋:
鴻蒙的網路組件只支援配置一個 DoH 連結,為提高業務穩定性,建議做好Local DNS降級
Network Kit 和 RCP 庫中,不支援配置自動降級到 Local DNS 的模式,請做好應用側降級,參考接入方案的範例程式碼。
ArkWeb 可以通過設定
SecureDnsMode為AUTO開啟允許自動降級到 Local DNS。
Network Kit 和 RCP 的 DoH 配置會受
addCustomDnsRule自訂解析規則的影響,如果您通過addCustomDnsRule配置了某些網域名稱的解析,那麼該網域名稱將不會再通過DoH 解析。
2. 前提條件
通過 DoH 接入 HarmonyOS 下“網路程式庫或組件”前,請您確保已經完成配置DoH服務。
3. Network Kit(httpRequest)接入 DoH
通過 Network Kit 在單次請求上指定http.request(options: http.RequestOptions)中的options.dnsOverHttps: string為您的 DoH 存取點,即可開啟 DoH,無需改造全域會話。範例程式碼如下:
import http from '@ohos.net.http';
const httpRequest: http.HttpRequest = http.createHttp();
// 這裡請替換為您自己的 DoH URL
const DOH_ENDPOINT = 'https://xxxxx.aliyunhttpdns.com/dns-query';
const isDoHFailure = (err: ErrorDetails): boolean => {
const code = String(err.code ?? '');
const msg = String(err.message ?? '');
return /(couldn'?t\s+resolve\s+host\s+name|resolve\s+host\s+name|dns|resolve|name\s*not\s*resolved|EAI_AGAIN)/i.test(msg) || /DNS/i.test(code);
};
httpRequest.request(this.urlInput, {
method: http.RequestMethod.GET,
connectTimeout: 3000,
readTimeout: 3000,
dnsOverHttps: DOH_ENDPOINT,
}).then((res: http.HttpResponse) => {
console.log('DoH request success:', res);
}).catch((err: ErrorDetails) => {
if (isDoHFailure(err)) {
console.error('DoH request error, falling back to local DNS:', err);
httpRequest.request(this.urlInput, {
method: http.RequestMethod.GET,
connectTimeout: 3000,
readTimeout: 3000,
}).then((fallbackRes: http.HttpResponse) => {
console.log('Fallback request success:', fallbackRes);
}).catch((fallbackErr: ErrorDetails) => {
console.error('Fallback request error:', fallbackErr);
});
} else {
console.error('Request error:', err);
}
});4. Remote Communication Kit(RCP)接入 DoH
RCP 網路程式庫支援在全域 Session 和 單個 Request 兩個不同粒度下接入 DoH, 下面介紹對應的接入方式。
4.1 Session 接入 DoH
通過 RCP 在會話層面上指定SessionConfiguration.requestConfiguration.dns.dnsOverHttps為您的 DoH 存取點,即可開啟 DoH,無需改造全域會話。範例程式碼如下:
import { rcp } from '@kit.RemoteCommunicationKit';
import type { BusinessError } from '@ohos.base';
private isDoHFailure(err: BusinessError): boolean {
const code: string = err.code ? String(err.code) : '';
const msg: string = String(err.data);
return /(couldn'?t\s+resolve\s+host\s+name|resolve\s+host\s+name|dns|resolve|name\s*not\s*resolved|EAI_AGAIN)/i.test(msg) || /DNS/i.test(code);
}
async sendRequest() {
try {
const dohConfig: rcp.DnsOverHttpsConfiguration = {
url: 'https://xxxxx.aliyunhttpdns.com/dns-query',
skipCertificatesValidation: false,
};
const dohSession = rcp.createSession({
requestConfiguration: {
dns: { dnsOverHttps: dohConfig },
transfer: { timeout: { connectMs: 3000, transferMs: 8000 } },
},
});
const resp = await dohSession.get(this.urlInput);
console.info('DoH request success, status=', resp.statusCode);
console.info('Response:', JSON.stringify(resp));
} catch (err) {
if (this.isDoHFailure(err)) {
console.error('DoH request error, falling back to local DNS:', err);
try {
const localSession = rcp.createSession({
requestConfiguration: { transfer: { timeout: { connectMs: 3000, transferMs: 8000 } } },
});
const fb = await localSession.get(this.urlInput);
console.info('Fallback (local DNS) success, status=', fb.statusCode);
console.info('Fallback response:', JSON.stringify(fb));
} catch (fallbackErr) {
console.error('Fallback (local DNS) request error:', fallbackErr);
}
} else {
console.error('Request error (non-DoH):', err);
}
}
}4.2 Request 接入 DoH
通過 RCP 在單次請求上指定 request.configuration.dns.dnsOverHttps為您的 DoH 存取點,即可開啟 DoH,無需改造全域會話。範例程式碼如下:
import { rcp } from '@kit.RemoteCommunicationKit';
import type { BusinessError } from '@ohos.base';
async sendRequest() {
try {
const dohConfig: rcp.DnsOverHttpsConfiguration = {
url: 'https://xxxxx.aliyunhttpdns.com/dns-query',
skipCertificatesValidation: false,
};
const session = rcp.createSession({
requestConfiguration: {
transfer: { timeout: { connectMs: 3000, transferMs: 8000 } },
},
});
const perReq = new rcp.Request(this.urlInput, 'GET', undefined, undefined, undefined, undefined, {
dns: { dnsOverHttps: dohConfig },
});
const resp = await session.fetch(perReq);
console.info('DoH request success, status=', resp.statusCode);
console.info('Response:', JSON.stringify(resp));
} catch (err) {
if (this.isDoHFailure(err)) {
console.error('DoH request error, falling back to local DNS:', err);
try {
const localSession = rcp.createSession({
requestConfiguration: { transfer: { timeout: { connectMs: 3000, transferMs: 8000 } } },
});
const fb = await localSession.get(this.urlInput);
console.info('Fallback (local DNS) success, status=', fb.statusCode);
console.info('Fallback response:', JSON.stringify(fb));
} catch (fallbackErr) {
console.error('Fallback (local DNS) request error:', fallbackErr);
}
} else {
console.error('Request error (non-DoH):', err);
}
}
}5. WebView 的 DoH 策略
通過 webview.WebviewController.setHttpDns指定您的 DoH URL,範例程式碼如下:
import { webview } from '@kit.ArkWeb';
webview.WebviewController.setHttpDns(webview.SecureDnsMode.AUTO, 'https://xxxxx.aliyunhttpdns.com/dns-query');鴻蒙的網路組件只支援配置一個 DoH 連結,為提高業務穩定性,建議做好Local DNS降級,ArkWeb 可以通過設定SecureDnsMode為AUTO開啟允許自動降級到 Local DNS。
6. 總結
通過本文檔介紹的步驟,您可以成功在 鴻蒙網路程式庫中整合DNS over HTTPS (DoH)功能,從而顯著提升應用程式的安全性和使用者隱私保護能力。配置後可通過將手機 WIFI 網路的 DNS 伺服器設定為一個無效地址,觀察業務請求是否依然能夠正常發起,以此判斷 DoH 是否接入成功。