aliyun_httpdns 1.0.0 copy "aliyun_httpdns: ^1.0.0" to clipboard
aliyun_httpdns: ^1.0.0 copied to clipboard

Aliyun HTTPDNS Flutter plugin.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'net/httpdns_http_client_adapter.dart';
import 'package:aliyun_httpdns/aliyun_httpdns.dart';

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HTTP Request Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'HTTP Request Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

enum NetworkLibrary {
  dio('Dio'),
  httpClient('HttpClient'),
  httpPackage('http');

  const NetworkLibrary(this.displayName);
  final String displayName;
}

class _MyHomePageState extends State<MyHomePage> {
  final TextEditingController _urlController = TextEditingController();
  String _responseText = 'Response will appear here...';
  bool _isLoading = false;

  late final Dio _dio;
  late final HttpClient _httpClient;
  late final http.Client _httpPackageClient;

  NetworkLibrary _selectedLibrary = NetworkLibrary.dio;

  bool _httpdnsReady = false;
  bool _httpdnsIniting = false;

  Future<void> _initHttpDnsOnce() async {
    if (_httpdnsReady || _httpdnsIniting) return;
    _httpdnsIniting = true;
    try {
      await AliyunHttpdns.init(
        accountId: 139450,
        secretKey: '807a19762f8eaefa8563489baf198535',
      );
      await AliyunHttpdns.setHttpsRequestEnabled(true);
      await AliyunHttpdns.setLogEnabled(true);
      await AliyunHttpdns.setPersistentCacheIPEnabled(true);
      await AliyunHttpdns.setReuseExpiredIPEnabled(true);
      await AliyunHttpdns.build();

      // 先build再执行解析相关动作
      final preResolveHosts = 'www.aliyun.com';
      await AliyunHttpdns.setPreResolveHosts([preResolveHosts], ipType: 'both');
      debugPrint('[httpdns] pre-resolve scheduled for host=$preResolveHosts');
      _httpdnsReady = true;
    } catch (e) {
      debugPrint('[httpdns] init failed: $e');
    } finally {
      _httpdnsIniting = false;
    }
  }

  @override
  void initState() {
    super.initState();
    // 设置默认的API URL用于演示
    _urlController.text = 'https://www.aliyun.com';

    // 仅首次进入页面时初始化 HTTPDNS
    _initHttpDnsOnce();

    // 先初始化HTTPDNS再初始化Dio
    _dio = Dio();
    _dio.httpClientAdapter = buildHttpdnsHttpClientAdapter();
    _dio.options.headers['Connection'] = 'keep-alive';

    _httpClient = buildHttpdnsNativeHttpClient();
    _httpPackageClient = buildHttpdnsHttpPackageClient();
  }

  @override
  void dispose() {
    _urlController.dispose();
    _httpClient.close();
    _httpPackageClient.close();
    super.dispose();
  }

  Future<void> _sendHttpRequest() async {
    if (_urlController.text.isEmpty) {
      setState(() {
        _responseText = 'Error: Please enter a URL';
      });
      return;
    }

    setState(() {
      _isLoading = true;
      _responseText = 'Sending request...';
    });

    final uri = Uri.parse(_urlController.text);

    try {
      final String libraryName = _selectedLibrary.displayName;
      debugPrint('[$libraryName] Sending request to ${uri.host}:${uri.port}');

      int statusCode;
      Map<String, String> headers;
      String body;

      switch (_selectedLibrary) {
        case NetworkLibrary.dio:
          final response = await _dio.getUri(
            uri,
            options: Options(
              responseType: ResponseType.plain,
              followRedirects: true,
              validateStatus: (_) => true,
            ),
          );
          statusCode = response.statusCode ?? 0;
          headers = {
            for (final e in response.headers.map.entries)
              e.key: e.value.join(','),
          };
          body = response.data is String
              ? response.data as String
              : jsonEncode(response.data);
          break;

        case NetworkLibrary.httpClient:
          final request = await _httpClient.getUrl(uri);
          final response = await request.close();
          statusCode = response.statusCode;
          headers = {};
          response.headers.forEach((name, values) {
            headers[name] = values.join(',');
          });
          body = await response.transform(utf8.decoder).join();
          break;

        case NetworkLibrary.httpPackage:
          final response = await _httpPackageClient.get(uri);
          statusCode = response.statusCode;
          headers = response.headers;
          body = response.body;
          break;
      }

      setState(() {
        _isLoading = false;

        final StringBuffer responseInfo = StringBuffer();

        responseInfo.writeln('=== REQUEST ($libraryName) ===');
        responseInfo.writeln('uri: ${uri.toString()}');
        responseInfo.writeln();

        responseInfo.writeln('=== STATUS ===');
        responseInfo.writeln('statusCode: $statusCode');
        responseInfo.writeln();

        responseInfo.writeln('=== HEADERS ===');
        headers.forEach((key, value) {
          responseInfo.writeln('$key: $value');
        });
        responseInfo.writeln();

        responseInfo.writeln('=== BODY ===');
        if (statusCode >= 200 && statusCode < 300) {
          try {
            final jsonData = json.decode(body);
            const encoder = JsonEncoder.withIndent('  ');
            responseInfo.write(encoder.convert(jsonData));
          } catch (_) {
            responseInfo.write(body);
          }
        } else {
          responseInfo.write(body);
        }

        _responseText = responseInfo.toString();
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
        _responseText = 'Network Error: $e';
      });
    }
  }

  // 使用 HTTPDNS 解析当前 URL 的 host 并显示结果
  Future<void> _testHttpDnsResolve() async {
    final text = _urlController.text.trim();
    if (text.isEmpty) {
      setState(() {
        _responseText = 'Error: Please enter a URL';
      });
      return;
    }

    final Uri uri;
    try {
      uri = Uri.parse(text);
    } catch (_) {
      setState(() {
        _responseText = 'Error: Invalid URL';
      });
      return;
    }

    setState(() {
      _isLoading = true;
      _responseText = 'Resolving with HTTPDNS...';
    });

    try {
      // 确保只初始化一次
      await _initHttpDnsOnce();
      final res = await AliyunHttpdns.resolveHostSyncNonBlocking(
        uri.host,
        ipType: 'both',
      );
      setState(() {
        _isLoading = false;
        final buf = StringBuffer();
        buf.writeln('=== HTTPDNS RESOLVE ===');
        buf.writeln('host: ${uri.host}');
        final ipv4 = (res['ipv4'] as List?)?.cast<String>() ?? const <String>[];
        final ipv6 = (res['ipv6'] as List?)?.cast<String>() ?? const <String>[];
        if (ipv4.isNotEmpty) buf.writeln('IPv4 list: ${ipv4.join(', ')}');
        if (ipv6.isNotEmpty) buf.writeln('IPv6 list: ${ipv6.join(', ')}');
        _responseText = buf.toString();
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
        _responseText = 'HTTPDNS Error: $e';
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // URL输入框
            TextField(
              controller: _urlController,
              decoration: const InputDecoration(
                labelText: 'Enter URL',
                hintText: 'https://www.aliyun.com',
                border: OutlineInputBorder(),
                prefixIcon: Icon(Icons.link),
              ),
              keyboardType: TextInputType.url,
            ),
            const SizedBox(height: 16),

            Row(
              children: [
                Expanded(
                  flex: 3,
                  child: ElevatedButton.icon(
                    onPressed: _isLoading ? null : _sendHttpRequest,
                    icon: _isLoading
                        ? const SizedBox(
                            width: 20,
                            height: 20,
                            child: CircularProgressIndicator(strokeWidth: 2),
                          )
                        : const Icon(Icons.send),
                    label: Text(_isLoading ? 'Sending...' : 'Send Request'),
                    style: ElevatedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(vertical: 12),
                    ),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  flex: 2,
                  child: Container(
                    padding: const EdgeInsets.symmetric(horizontal: 12),
                    decoration: BoxDecoration(
                      border: Border.all(color: Colors.grey),
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: DropdownButton<NetworkLibrary>(
                      value: _selectedLibrary,
                      isExpanded: true,
                      underline: const SizedBox(),
                      icon: const Icon(Icons.arrow_drop_down),
                      items: NetworkLibrary.values.map((library) {
                        return DropdownMenuItem<NetworkLibrary>(
                          value: library,
                          child: Text(library.displayName),
                        );
                      }).toList(),
                      onChanged: _isLoading
                          ? null
                          : (NetworkLibrary? newValue) {
                              if (newValue != null) {
                                setState(() {
                                  _selectedLibrary = newValue;
                                });
                              }
                            },
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 16),

            // HTTPDNS 解析按钮
            ElevatedButton.icon(
              onPressed: _isLoading ? null : _testHttpDnsResolve,
              icon: const Icon(Icons.dns),
              label: const Text('HTTPDNS Resolve'),
              style: ElevatedButton.styleFrom(
                padding: const EdgeInsets.symmetric(vertical: 12),
              ),
            ),
            const SizedBox(height: 16),

            // 保留空白分隔
            const SizedBox(height: 16),

            // 响应文本显示区域
            Expanded(
              child: Container(
                width: double.infinity,
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey),
                  borderRadius: BorderRadius.circular(8),
                  color: Colors.grey.shade50,
                ),
                child: SingleChildScrollView(
                  child: Text(
                    _responseText,
                    style: const TextStyle(
                      fontFamily: 'monospace',
                      fontSize: 12,
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
145
points
230
downloads

Publisher

unverified uploader

Weekly Downloads

Aliyun HTTPDNS Flutter plugin.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on aliyun_httpdns

Packages that implement aliyun_httpdns