Flutter DNS查询插件doh_api_client的使用

Flutter DNS查询插件doh_api_client的使用

特性

  • 使用DNS over HTTPS (DoH)协议进行HTTP请求(GET, POST, PUT, PATCH, DELETE)
  • 支持12种不同的DoH提供商
  • 易于与Flutter项目集成
  • 原生实现以提高性能(Android上使用OKHTTP,iOS上使用URLSession)

安装

pubspec.yaml文件中添加以下依赖:

dependencies:
  doh_api_client: ^1.0.0

然后运行:

flutter pub get

使用方法

首先,在你的Dart文件中导入插件:

import 'package:doh_api_client/doh_api_client.dart';
发送API请求

以下是如何使用DoH API客户端发送POST请求的示例:

final _dohApiClientPlugin = DohApiClient();

try {
  String apiPostRequest = await _dohApiClientPlugin.post(
    url: "https://jsonplaceholder.typicode.com/posts",
    headers: {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
      'Content-type': 'application/json; charset=UTF-8'
    },
    body: jsonEncode({
      "title": 'foo',
      "body": 'bar',
      "userId": 1,
    }),
    dohProvider: DohProvider.CloudFlare
  );
  print(apiPostRequest);
} catch (e) {
  print("Error occurred: $e");
}
可用的DoH提供商

该插件支持以下DoH提供商:

  • CloudFlare
  • Google
  • AdGuard
  • Quad9
  • AliDNS
  • DNSPod
  • threeSixty
  • Quad101
  • Mullvad
  • ControlD
  • Najalla
  • SheCan

你可以通过DohProvider枚举指定DoH提供商。

API参考

DohApiClient

这是用于发送API请求的主要类。

方法
  • Future<String?> get({required String url, Map<String, String>? headers, DohProvider dohProvider})
  • Future<String?> post({required String url, Map<String, String>? headers, required String body, DohProvider dohProvider})
  • Future<String?> put({required String url, Map<String, String>? headers, required String body, DohProvider dohProvider})
  • Future<String?> patch({required String url, Map<String, String>? headers, required String body, DohProvider dohProvider})
  • Future<String?> delete({required String url, Map<String, String>? headers, DohProvider dohProvider})

示例代码

import 'dart:convert';

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:doh_api_client/doh_api_client.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _dohApiClientPlugin = DohApiClient();
  String _apiGetRequest = "";
  String _apiPostRequest = "";
  String _apiPutRequest = "";
  String _apiPatchRequest = "";
  String _apiDeleteRequest = "";

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
  }

  // 平台消息是异步的,所以我们初始化时使用异步方法。
  Future<void> initPlatformState() async {
    String apiGetRequest;
    String apiPostRequest;
    String apiPutRequest;
    String apiPatchRequest;
    String apiDeleteRequest;

    // 平台消息可能失败,所以我们使用try/catch处理PlatformException。
    // 我们还处理消息可能返回null的情况。

    try {
      apiGetRequest = await _dohApiClientPlugin.get(
              url: "https://jsonplaceholder.typicode.com/posts/1",
              headers: {
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
              },
              dohProvider: DohProvider.CloudFlare) ??
          "Method Channel Called for GET Request but Failure Received";
      setState(() {
        _apiGetRequest = apiGetRequest;
      });
    } catch (e) {
      apiGetRequest = "Method Channel Failed to call for GET Request";
      setState(() {
        _apiGetRequest = apiGetRequest;
      });
    }

    try {
      apiPostRequest = await _dohApiClientPlugin.post(
              url: "https://jsonplaceholder.typicode.com/posts",
              headers: {
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
                'Content-type': 'application/json; charset=UTF-8'
              },
              body: jsonEncode({
                "title": 'foo',
                "body": 'bar',
                "userId": 1,
              }),
              dohProvider: DohProvider.CloudFlare) ??
          "Method Channel Called for POST Request but Failure Received";
      setState(() {
        _apiPostRequest = apiPostRequest;
      });
    } catch (e) {
      apiPostRequest = "Method Channel Failed to call for POST Request";
      setState(() {
        _apiPostRequest = apiPostRequest;
      });
    }

    try {
      apiPutRequest = await _dohApiClientPlugin.put(
              url: "https://jsonplaceholder.typicode.com/posts/1",
              headers: {
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
                'Content-type': 'application/json; charset=UTF-8'
              },
              body: jsonEncode({
                "id": 1,
                "title": 'foo',
                "body": 'bar',
                "userId": 1,
              }),
              dohProvider: DohProvider.CloudFlare) ??
          "Method Channel Called for PUT Request but Failure Received";
      setState(() {
        _apiPutRequest = apiPutRequest;
      });
    } catch (e) {
      apiPutRequest = "Method Channel Failed to call for PUT Request";
      setState(() {
        _apiPutRequest = apiPutRequest;
      });
    }

    try {
      apiPatchRequest = await _dohApiClientPlugin.patch(
              url: "https://jsonplaceholder.typicode.com/posts/1",
              headers: {
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
                'Content-type': 'application/json; charset=UTF-8'
              },
              body: jsonEncode({
                "title": 'foo',
              }),
              dohProvider: DohProvider.CloudFlare) ??
          "Method Channel Called for PATCH Request but Failure Received";
      setState(() {
        _apiPatchRequest = apiPatchRequest;
      });
    } catch (e) {
      apiPatchRequest = "Method Channel Failed to call for PATCH Request";
      setState(() {
        _apiPatchRequest = apiPatchRequest;
      });
    }

    try {
      apiDeleteRequest = await _dohApiClientPlugin.delete(
              url: "https://jsonplaceholder.typicode.com/posts/1",
              headers: {
                "User-Agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
              },
              dohProvider: DohProvider.CloudFlare) ??
          "Method Channel Called for DELETE Request but Failure Received";
      setState(() {
        _apiDeleteRequest = apiDeleteRequest;
      });
    } catch (e) {
      apiDeleteRequest = "Method Channel Failed to call for DELETE Request";
      setState(() {
        _apiDeleteRequest = apiDeleteRequest;
      });
    }
    // 如果小部件从树中被移除,而异步平台消息还在飞行中,我们希望丢弃回复而不是调用setState来更新我们的不存在的外观。
    if (!mounted) return;
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('DoH API Client Example'),
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("GET Request: "),
                    _apiGetRequest.isEmpty
                        ? const CircularProgressIndicator()
                        : Expanded(child: Text(_apiGetRequest)),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("POST Request: "),
                    _apiPostRequest.isEmpty
                        ? const CircularProgressIndicator()
                        : Expanded(child: Text(_apiPostRequest)),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("PUT Request: "),
                    _apiPutRequest.isEmpty
                        ? const CircularProgressIndicator()
                        : Expanded(child: Text(_apiPutRequest)),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("PATCH Request: "),
                    _apiPatchRequest.isEmpty
                        ? const CircularProgressIndicator()
                        : Expanded(child: Text(_apiPatchRequest)),
                  ],
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text("DELETE Request: "),
                    _apiDeleteRequest.isEmpty
                        ? const CircularProgressIndicator()
                        : Expanded(child: Text(_apiDeleteRequest)),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter DNS查询插件doh_api_client的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter DNS查询插件doh_api_client的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用doh_api_client插件进行DNS查询的示例代码。doh_api_client是一个支持DNS over HTTPS(DoH)的Flutter插件,可以用于在Flutter应用中执行DNS查询。

首先,确保你已经在pubspec.yaml文件中添加了doh_api_client依赖:

dependencies:
  flutter:
    sdk: flutter
  doh_api_client: ^最新版本号  # 请替换为实际的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,你可以在你的Flutter应用中使用这个插件来执行DNS查询。以下是一个简单的示例代码:

import 'package:flutter/material.dart';
import 'package:doh_api_client/doh_api_client.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String? result;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('DoH DNS Query Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(labelText: 'Enter domain name'),
                onEditingComplete: () async {
                  String domain = this.textEditingController.text;
                  result = await performDnsQuery(domain);
                  setState(() {});
                },
                // 为了简化示例,这里直接使用了onEditingComplete,实际应用中可能需要一个按钮来触发查询
                controller: TextEditingController()..addListener(() {
                  if (!this.textEditingController.text.contains('.')) {
                    // 简单验证,确保输入的是域名
                    this.textEditingController.value =
                        this.textEditingController.value.copyWith(
                          text: this.textEditingController.text,
                          composing: TextRange.empty,
                          selection: TextSelection.collapsed(offset: this.textEditingController.text.length),
                        );
                  }
                }),
              ),
              SizedBox(height: 20),
              if (result != null) Text('Result: $result'),
            ],
          ),
        ),
      ),
    );
  }

  Future<String?> performDnsQuery(String domain) async {
    try {
      // 创建一个DoH客户端实例
      final DohApiClient dohClient = DohApiClient(
        url: 'https://dns.google/resolve',  // 你可以使用其他DoH服务器,比如Cloudflare的 'https://1.1.1.1/dns-query'
      );

      // 执行DNS查询
      final response = await dohClient.query(domain);

      // 处理响应结果
      if (response.status == 0) {
        // 查询成功,这里只提取第一个A记录作为示例
        final firstARecord = response.answer
            ?.firstWhereOrNull((record) => record.type == RecordType.A)
            as? ARecord;

        if (firstARecord != null) {
          return 'IP Address: ${firstARecord.ip}';
        } else {
          return 'No A record found.';
        }
      } else {
        return 'Error: ${response.statusMessage}';
      }
    } catch (e) {
      return 'Exception: $e';
    }
  }
}

请注意,这个示例代码中有几个关键点:

  1. TextFormField 用于输入域名,并在编辑完成时触发DNS查询。
  2. DohApiClient 用于执行DNS查询,这里使用了Google的DoH服务器(https://dns.google/resolve),你可以根据需要更改为其他DoH服务器。
  3. performDnsQuery 方法执行DNS查询并处理响应结果,这里只提取了第一个A记录作为示例。

请根据你的实际需求调整代码,并确保你的应用有适当的错误处理和用户反馈机制。

回到顶部