__init__.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. from flask import Flask, jsonify
  2. from flask_sqlalchemy import SQLAlchemy
  3. from flask_cors import CORS
  4. import logging
  5. from app.config.config import config, current_env
  6. import os
  7. db = SQLAlchemy()
  8. def create_app():
  9. """Create and configure the Flask application"""
  10. app = Flask(__name__)
  11. # 加载配置
  12. app.config.from_object(config[current_env])
  13. # 初始化扩展
  14. CORS(app)
  15. db.init_app(app)
  16. # 注册蓝图
  17. from app.api.meta_data import bp as meta_bp
  18. from app.api.data_resource import bp as resource_bp
  19. from app.api.data_model import bp as data_model_bp
  20. from app.api.data_interface import bp as data_interface_bp
  21. from app.api.data_metric import bp as data_metric_bp
  22. from app.api.production_line import bp as production_line_bp
  23. from app.api.graph import bp as graph_bp
  24. from app.api.system import bp as system_bp
  25. from app.api.data_source import bp as data_source_bp
  26. from app.api.data_parse import bp as data_parse_bp
  27. from app.api.data_flow import bp as data_flow_bp
  28. app.register_blueprint(meta_bp, url_prefix='/api/meta')
  29. app.register_blueprint(resource_bp, url_prefix='/api/resource')
  30. app.register_blueprint(data_model_bp, url_prefix='/api/model')
  31. app.register_blueprint(data_interface_bp, url_prefix='/api/interface')
  32. app.register_blueprint(data_metric_bp, url_prefix='/api/metric')
  33. app.register_blueprint(production_line_bp, url_prefix='/api/pipeline')
  34. app.register_blueprint(graph_bp, url_prefix='/api/graph')
  35. app.register_blueprint(system_bp, url_prefix='/api/system')
  36. app.register_blueprint(data_source_bp, url_prefix='/api/datasource')
  37. app.register_blueprint(data_parse_bp, url_prefix='/api/parse')
  38. app.register_blueprint(data_flow_bp, url_prefix='/api/dataflow')
  39. # Configure global response headers
  40. configure_response_headers(app)
  41. # Configure logging
  42. configure_logging(app)
  43. # 添加全局异常处理器
  44. configure_error_handlers(app)
  45. # 输出启动信息
  46. app.logger.info(f"Starting server in {current_env} mode on port {app.config['PORT']}")
  47. return app
  48. def configure_response_headers(app):
  49. """Configure global response headers for JSON content"""
  50. @app.after_request
  51. def after_request(response):
  52. from flask import request
  53. # 检查是否是API路径
  54. if request.path.startswith('/api/'):
  55. # 排除文件下载和特殊响应类型
  56. if (response.content_type and
  57. any(ct in response.content_type for ct in [
  58. 'application/octet-stream',
  59. 'application/pdf',
  60. 'image/',
  61. 'text/csv',
  62. 'application/vnd.ms-excel',
  63. 'application/vnd.openxmlformats-officedocument'
  64. ])):
  65. # 保持原有的文件类型不变
  66. pass
  67. elif response.content_type and 'application/json' in response.content_type:
  68. # 确保JSON响应设置正确的Content-Type和charset
  69. response.headers['Content-Type'] = 'application/json; charset=utf-8'
  70. elif (not response.content_type or
  71. response.content_type == 'text/html; charset=utf-8' or
  72. response.content_type == 'text/plain'):
  73. # 对于API路由,如果没有明确设置Content-Type或设置为HTML,默认设置为JSON
  74. response.headers['Content-Type'] = 'application/json; charset=utf-8'
  75. return response
  76. def configure_logging(app):
  77. """Configure logging for the application"""
  78. if not app.config.get('LOG_ENABLED', True):
  79. return None
  80. log_file = app.config.get('LOG_FILE', f'flask_{app.config["FLASK_ENV"]}.log')
  81. log_level_name = app.config.get('LOG_LEVEL', 'INFO')
  82. log_level = getattr(logging, log_level_name)
  83. log_format = app.config.get('LOG_FORMAT', '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
  84. log_encoding = app.config.get('LOG_ENCODING', 'UTF-8')
  85. log_to_console = app.config.get('LOG_TO_CONSOLE', True)
  86. # 配置根日志器
  87. root_logger = logging.getLogger()
  88. root_logger.setLevel(log_level)
  89. # 清除所有现有处理器
  90. root_logger.handlers.clear()
  91. # 文件处理器 - 只添加到根日志器
  92. file_handler = logging.FileHandler(log_file, encoding=log_encoding)
  93. file_handler.setLevel(log_level)
  94. logging_format = logging.Formatter(log_format)
  95. file_handler.setFormatter(logging_format)
  96. root_logger.addHandler(file_handler)
  97. # 控制台处理器 - 只添加到根日志器
  98. if log_to_console:
  99. console = logging.StreamHandler()
  100. console.setLevel(log_level)
  101. console.setFormatter(logging_format)
  102. root_logger.addHandler(console)
  103. # 确保Flask内部日志器使用我们的配置
  104. app.logger.handlers.clear() # 移除Flask默认处理器
  105. # 配置app日志器,但禁止传播到根日志器
  106. logger = logging.getLogger("app")
  107. logger.setLevel(log_level)
  108. logger.handlers.clear() # 清除现有处理器
  109. logger.propagate = True # 通过根日志器处理
  110. app.logger.info(f"日志配置完成: 级别={log_level_name}, 文件={log_file}")
  111. return logger
  112. def configure_error_handlers(app):
  113. """Configure global error handlers for the application"""
  114. @app.errorhandler(Exception)
  115. def handle_exception(e):
  116. """全局异常处理器,捕获所有未处理的异常"""
  117. # 记录详细的错误信息
  118. app.logger.error(f"未处理的异常: {str(e)}", exc_info=True)
  119. # 返回标准化的错误响应
  120. error_response = {
  121. 'success': False,
  122. 'message': f'服务器内部错误: {str(e)}',
  123. 'data': None
  124. }
  125. return jsonify(error_response), 500
  126. @app.errorhandler(404)
  127. def handle_not_found(e):
  128. """处理404错误"""
  129. app.logger.warning(f"404错误: {str(e)}")
  130. return jsonify({
  131. 'success': False,
  132. 'message': '请求的资源不存在',
  133. 'data': None
  134. }), 404
  135. @app.errorhandler(500)
  136. def handle_internal_error(e):
  137. """处理500错误"""
  138. app.logger.error(f"500错误: {str(e)}", exc_info=True)
  139. return jsonify({
  140. 'success': False,
  141. 'message': '服务器内部错误',
  142. 'data': None
  143. }), 500