Skip to content

添加依赖

dart
dependencies:
    args: ^2.5.0
    http: ^0.13.5
    intl: ^0.18.0
    convert: ^3.0.0
    crypto: ^3.0.6
dart
import 'dart:convert';
import 'dart:math';

import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';

class UpgradeRequest {
  final String fileKey;
  final int versionCode;
  final int appointVersionCode;
  final String devModelKey;
  final String devKey;

  UpgradeRequest({
    required this.fileKey,
    required this.versionCode,
    this.appointVersionCode = 0,
    this.devModelKey = '',
    this.devKey = '',
  });

  Map<String, dynamic> toJson() => {
    'fileKey': fileKey,
    'versionCode': versionCode,
    'appointVersionCode': appointVersionCode,
    'devModelKey': devModelKey,
    'devKey': devKey,
  };
}

class UpgradeResponse {
  final int code;
  final String msg;
  final dynamic data;

  UpgradeResponse({
    required this.code,
    required this.msg,
    required this.data,
  });

  @override
  String toString() {
    return '''
UpgradeResponse:
  code: $code
  msg: $msg
  data: ${_formatData(data)}
''';
  }

  String _formatData(dynamic data) {
    if (data == null) return 'null';
    if (data is Map || data is List) {
      return const JsonEncoder.withIndent('  ').convert(data);
    }
    return data.toString();
  }

  factory UpgradeResponse.fromJson(Map<String, dynamic> json) =>
      UpgradeResponse(
        code: json['code'],
        msg: json['msg'],
        data: json['data'],
      );
  }

const accessKey = 'a1';
const secretKey = 'a2';
const apiUrl = 'http://api.upgrade.toolsetlink.com/v1/file/upgrade';

void main() async {
  // 1. 构造请求体
  final requestBody = UpgradeRequest(
    fileKey: 'key1',
    versionCode: 1,
    devModelKey: '12312',
    devKey: '12312',
  );

  // 2. 序列化请求体
  final bodyStr = jsonEncode(requestBody.toJson());

  // 3. 生成请求参数
  // 获取当前时间并转换为上海时区 RFC3339 时间格式
  DateTime now = DateTime.now().toUtc().add(const Duration(hours: 8));
  String timestamp = DateFormat("yyyy-MM-dd'T'HH:mm:ss").format(now) + "+08:00";

  final nonce = generateNonce();
  final uri = '/v1/file/upgrade';

  // 4. 生成签名
  final signature = generateSignature(
    body: bodyStr,
    nonce: nonce,
    secretKey: secretKey,
    timestamp: timestamp,
    uri: uri,
  );

  // 5. 创建HTTP请求
  final client = http.Client();
  try {
    final response = await client.post(
      Uri.parse(apiUrl),
      headers: {
        'X-Timestamp': timestamp,
        'X-Nonce': nonce,
        'X-AccessKey': accessKey,
        'X-Signature': signature,
        'Content-Type': 'application/json',
      },
      body: bodyStr,
    );

    // 6. 处理响应
    print('Status Code: ${response.statusCode}');
    if (response.body.isNotEmpty) {
      final result = UpgradeResponse.fromJson(
        jsonDecode(response.body) as Map<String, dynamic>,
      );
      print('Response: ${result.toString()}');
    }
  } finally {
    client.close();
  }
}

// 生成随机Nonce (16位十六进制)
String generateNonce() {
  final random = Random.secure();
  final bytes = List<int>.generate(8, (_) => random.nextInt(256));
  return hex.encode(bytes);
}

// 生成请求签名
String generateSignature({
  required String body,
  required String nonce,
  required String secretKey,
  required String timestamp,
  required String uri,
}) {
  final parts = <String>[];

  if (body.isNotEmpty) {
    parts.add('body=$body');
  }

  parts.addAll([
    'nonce=$nonce',
    'secretKey=$secretKey',
    'timestamp=$timestamp',
    'url=$uri',
  ]);

  final signStr = parts.join('&');
  final bytes = md5.convert(utf8.encode(signStr)).bytes;
  return hex.encode(bytes);
}