local_server.dart 4.47 KB
import 'dart:io';

import 'package:archive/archive.dart';
import 'package:flutter/services.dart';

late HttpServer localServer;

Future<void> startLocalServer() async {
  HttpServer localServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
  print('本地服务器启动在端口: ${localServer.port}');

  localServer.listen((HttpRequest request) async {
    final String requestPath = request.uri.path == '/' ? '/index.html' : request.uri.path;

    try {
      if (requestPath.startsWith('/temp/')) {
        // 临时目录文件的请求
        await _serveTempFile(request, requestPath);
      } else if (requestPath.startsWith('/test/')) {
        // assets文件服务逻辑
        await _serveAssetFile(request, requestPath);
      } else {
        // asset/dist.zip 文件服务逻辑
        await _serveZipFileContent(request, requestPath);
      }
    } catch (e) {
      print('处理请求时出错: $e');
      request.response
        ..statusCode = HttpStatus.internalServerError
        ..write('Internal server error')
        ..close();
    }
  });
}

// 临时目录的文件
Future<void> _serveTempFile(HttpRequest request, String requestPath) async {
  try {
    // 临时文件已经设备路径
    // 构建文件路径(移除 /temp 前缀)
    final String filePath = requestPath.substring('/temp/'.length);

    // 检查文件是否存在
    final File file = File(filePath);
    if (await file.exists()) {
      // 读取文件内容
      final List<int> bytes = await file.readAsBytes();

      request.response
        ..headers.contentType = ContentType.parse(_getContentType(filePath))
        ..add(bytes)
        ..close();
    } else {
      request.response
        ..statusCode = HttpStatus.notFound
        ..write('File not found: $filePath')
        ..close();
    }
  } catch (e) {
    print('读取临时文件时出错: $e');
    request.response
      ..statusCode = HttpStatus.notFound
      ..write('File not found')
      ..close();
  }
}

Future<void> _serveZipFileContent(HttpRequest request, String requestPath) async {
  String zipAssetPath = 'assets/dist.zip';

  try {
    // 使用 rootBundle.load 加载资源文件
    final ByteData data = await rootBundle.load(zipAssetPath);
    final List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

    // 读取并解压zip文件内容
    final Archive archive = ZipDecoder().decodeBytes(bytes);

    // 查找请求的内部文件
    ArchiveFile? targetFile;
    for (final file in archive) {
      // 标准化路径分隔符(统一使用 '/')
      String zipFileName = file.name.replaceAll('\\', '/');

      // 移除开头的 '/'(如果存在)
      if (requestPath.startsWith('/')) {
        requestPath = requestPath.substring(1);
      }

      if (zipFileName == requestPath) {
        targetFile = file;
        break;
      }
    }

    if (targetFile == null) {
      request.response
        ..statusCode = HttpStatus.notFound
        ..write('File not found in zip: $requestPath')
        ..close();
      return;
    }

    // 返回文件内容
    request.response
      ..headers.contentType = ContentType.parse(_getContentType(requestPath))
      ..add(targetFile.content as List<int>)
      ..close();
  } catch (e) {
    print('读取zip文件时出错: $e');
    request.response
      ..statusCode = HttpStatus.internalServerError
      ..write('Error reading zip file')
      ..close();
  }
}

// 访问assets目录下的文件
Future<void> _serveAssetFile(HttpRequest request, String requestPath) async {
  // 构建文件路径(移除 /test 前缀)
  final String path = requestPath.substring('/test'.length);
  final String filePath = 'assets$path';

  try {
    final ByteData data = await rootBundle.load(filePath);
    final List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

    request.response
      ..headers.contentType = ContentType.parse(_getContentType(filePath))
      ..add(bytes)
      ..close();
  } catch (e) {
    request.response
      ..statusCode = HttpStatus.notFound
      ..write('File not found: $filePath')
      ..close();
  }
}

String _getContentType(String filePath) {
  if (filePath.endsWith('.html')) return 'text/html';
  if (filePath.endsWith('.js')) return 'application/javascript';
  if (filePath.endsWith('.css')) return 'text/css';
  if (filePath.endsWith('.png')) return 'image/png';
  if (filePath.endsWith('.jpg') || filePath.endsWith('.jpeg')) return 'image/jpeg';
  return 'application/octet-stream';
}