File size: 2,190 Bytes
494c9e4
 
 
 
 
 
 
 
b704fe2
494c9e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82b33f3
c4753aa
494c9e4
 
 
 
 
 
 
c4753aa
494c9e4
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
"""静态文件路由"""
import mimetypes
from pathlib import Path
from urllib.parse import unquote

from flask import Response, redirect, abort, request
from werkzeug.utils import safe_join

from backend.access_log import log_cached_demo, log_json_demo, log_page_load


def _read_static_file(directory: str, path: str) -> Response:
    """读取静态文件并返回 Response,避免 send_from_directory 在 ASGI/a2wsgi 下
    流式传输导致的 Content-Length 不匹配(RuntimeError: Response content shorter than Content-Length)。
    """
    base = Path(directory).resolve()
    safe_path = safe_join(str(base), path)
    if safe_path is None:
        abort(404)
    full_path = Path(safe_path)
    if not full_path.is_file() or not str(full_path.resolve()).startswith(str(base)):
        abort(404)
    content = full_path.read_bytes()
    mimetype, _ = mimetypes.guess_type(path)
    mimetype = mimetype or "application/octet-stream"
    return Response(content, mimetype=mimetype, headers={"Content-Length": str(len(content))})


def register_static_routes(app):
    """注册静态文件路由"""
    
    @app.route('/')
    def redir():
        target = 'client/index.html'
        if request.query_string:
            target += '?' + request.query_string.decode()
        return redirect(target)

    @app.route('/client/<path:path>')
    def send_static(path):
        """serves all files from ./client/dist/ to ``/client/<path:path>``"""
        if path.endswith('.html'):
            log_page_load(path)
        if path.endswith('.json'):
            log_cached_demo(path)
        return _read_static_file('client/dist', path)

    @app.route('/demo/<path:path>')
    def send_demo(path):
        """serves all demo files from the demo dir to ``/demo/<path:path>``"""
        from backend.app_context import get_data_dir
        data_dir = get_data_dir()
        log_json_demo(path)
        try:
            decoded_path = unquote(path)
            return _read_static_file(str(data_dir), decoded_path)
        except Exception:
            try:
                return _read_static_file(str(data_dir), path)
            except Exception:
                abort(404)