【Flask】测试平台开发,集成禅道

发布于:2025-08-31 ⋅ 阅读:(25) ⋅ 点赞:(0)

概述:

由于公司多数测试人员还是在使用禅道,为了方便,就将禅道直接集成在我们的测试平台中

一般可以有几种实现方法

  • 调用禅道的API集成
  • 集成本地部署的禅道-可能有跨域问题,需要解决

由于我这里已经部署了一台本地的禅道系统,那么这里我将以最简单的方式集成,通过代理集成到测试平台系统中,代理这里我们又可以分为以下方式

  • 前端vue代理
  • 后端代理
  • Nginx代理

一般我们选择nginx这种方式进行集成,能够高并发,满足业务需求使用,先来看看本地开发环境式如何使用

访问nginx的官网下载nginx

nginx

首页如下

在这里我下载的是中间的稳定版本下载在本地你任意一个磁盘,然后解压,解压后效果如下

打开nginx的配置文件,配置如下

worker_processes  1;
events { worker_connections  1024; }

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       81;
        server_name  172.16.60.60;

        # 前端系统代理(Vue)
        location / {
            proxy_pass http://localhost:9528;
            proxy_set_header Host $host:$server_port;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # 禅道代理(完美复刻直接访问环境)
        location /zentao/ {
            # 1. 目标地址:禅道服务器(与直接访问完全一致)
            proxy_pass http://172.16.50.80/zentao/;

            # 2. 复刻直接访问的请求头(关键!)
            proxy_set_header Host 172.16.50.80;  # 强制使用禅道原始 Host(直接访问时的 Host)
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header Referer http://172.16.50.80/zentao/;  # 模拟原域名 Referer
            proxy_set_header User-Agent $http_user_agent;  # 传递客户端浏览器信息

            # 3. 复刻直接访问的 Cookie 环境(核心!)
            proxy_cookie_path / /;  # Cookie 路径与直接访问一致(根路径 /)
            proxy_cookie_domain 172.16.50.80 172.16.60.60;  # 将 Cookie 域名为 Nginx 服务器 IP

            # 4. 关闭 Nginx 缓冲(确保请求与直接访问完全一致)
            proxy_request_buffering off;
            proxy_buffering off;

            # 5. 移除安全限制头(允许表单提交和跳转)
            proxy_hide_header Content-Security-Policy;
            proxy_hide_header X-Frame-Options;

            # 6. 重定向处理(登录后跳转 Nginx 地址)
            proxy_redirect http://172.16.50.80/ http://172.16.60.60:81/;  # 注意末尾斜杠!
        }
    }
}

注意

ngin每次配置操作,启用时最好都检查一下语法,windows操作命令如下

nginx -t 检查语法
nginx -s reload 重启nginx
nginx -s stop 停用
start nginx 启动

编写前端vue的页面展示部分以及路由

<template>
  <div class="zentao-container">
    <!-- 尺寸控制栏 -->
    <div class="zentao-header">
      <div class="header-title">禅道项目管理系统(rebort)</div>
      <div class="header-actions">
        <!-- 全屏切换按钮 -->
        <el-button
          icon="el-icon-full-screen"
          size="mini"
          @click="toggleFullScreen"
          :title="isFullScreen ? '退出全屏' : '进入全屏'"
        />
        <!-- 固定尺寸按钮(可选) -->
        <el-button
          icon="el-icon-sizer"
          size="mini"
          @click="resetSize"
          title="重置尺寸"
        />
      </div>
    </div>
    <!-- 禅道 iframe -->
    <iframe
      ref="zentaoIframe"
      :src="iframeSrc"
      class="zentao-iframe"
      :style="{ height: iframeHeight, width: iframeWidth }"
      sandbox="allow-same-origin allow-scripts allow-forms allow-top-navigation allow-popups"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      iframeSrc: '/zentao/user-login.html', // 禅道登录页地址
      iframeWidth: '100%', // 初始宽度(可固定为具体值,如 '1200px')
      iframeHeight: '80vh', // 初始高度(80% 视窗高度,避免全屏)
      isFullScreen: false // 全屏状态标记
    };
  },
  methods: {
    // 切换全屏/退出全屏
    toggleFullScreen() {
      const container = document.querySelector('.zentao-container');
      if (!this.isFullScreen) {
        // 进入全屏
        if (container.requestFullscreen) {
          container.requestFullscreen();
        } else if (container.mozRequestFullScreen) { // Firefox
          container.mozRequestFullScreen();
        } else if (container.webkitRequestFullscreen) { // Chrome/Safari
          container.webkitRequestFullscreen();
        } else if (container.msRequestFullscreen) { // IE/Edge
          container.msRequestFullscreen();
        }
        this.isFullScreen = true;
      } else {
        // 退出全屏
        if (document.exitFullscreen) {
          document.exitFullscreen();
        } else if (document.mozCancelFullScreen) {
          document.mozCancelFullScreen();
        } else if (document.webkitExitFullscreen) {
          document.webkitExitFullscreen();
        } else if (document.msExitFullscreen) {
          document.msExitFullscreen();
        }
        this.isFullScreen = false;
      }
    },
    // 重置尺寸为初始值
    resetSize() {
      this.iframeWidth = '100%';
      this.iframeHeight = '80vh';
      this.isFullScreen = false;
      // 若处于全屏状态,先退出全屏
      if (document.fullscreenElement) {
        document.exitFullscreen();
      }
    }
  },
  mounted() {
    // 监听全屏状态变化(处理用户按 ESC 退出全屏的情况)
    document.addEventListener('fullscreenchange', () => {
      this.isFullScreen = !!document.fullscreenElement;
    });
    document.addEventListener('mozfullscreenchange', () => {
      this.isFullScreen = !!document.mozFullScreenElement;
    });
    document.addEventListener('webkitfullscreenchange', () => {
      this.isFullScreen = !!document.webkitFullscreenElement;
    });
    document.addEventListener('msfullscreenchange', () => {
      this.isFullScreen = !!document.msFullscreenElement;
    });
  }
};
</script>

<style scoped>
/* 容器样式 */
.zentao-container {
  position: relative;
  width: 100%;
  border: 1px solid #e6e6e6;
  border-radius: 4px;
  overflow: hidden;
}

/* 头部控制栏 */
.zentao-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background-color: #f5f5f5;
  border-bottom: 1px solid #e6e6e6;
}

.header-title {
  font-weight: 500;
  color: #333;
}

.header-actions {
  display: flex;
  gap: 8px;
}

/* iframe 样式 */
.zentao-iframe {
  border: none;
  transition: all 0.3s ease;
}

/* 全屏状态样式(可选) */
::v-deep .zentao-container:fullscreen {
  background-color: #fff;
  z-index: 9999;
}
::v-deep .zentao-container:-webkit-full-screen {
  background-color: #fff;
  z-index: 9999;
}
</style>

最终集成后效果如下

 

如果是在生产环境下使用,我们可能会考虑使用加密的方式

server {
    listen 443 ssl;  # 监听 HTTPS 端口
    server_name project.example.com;  # 生产环境域名

    # SSL 证书配置(替换为实际证书路径)
    ssl_certificate /etc/nginx/ssl/project.crt;
    ssl_certificate_key /etc/nginx/ssl/project.key;

    # SSL 安全配置
    ssl_protocols TLSv1.2 TLSv1.3;  # 禁用不安全协议
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # 强制 HTTP 跳转 HTTPS
    return 301 https://$host$request_uri;
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name project.example.com;
    return 301 https://$host$request_uri;
}

限制请求速率,防止攻击

http {
    # 配置请求限制
    limit_req_zone $binary_remote_addr zone=zentao_req:10m rate=10r/s;  # 限制单 IP 10 请求/秒
    limit_conn_zone $binary_remote_addr zone=zentao_conn:10m;  # 限制并发连接
}

server {
    location /zentao/ {
        proxy_pass http://172.16.50.80/zentao/;
        # 应用请求限制
        limit_req zone=zentao_req burst=20 nodelay;  # 突发允许 20 请求
        limit_conn zentao_conn 50;  # 单 IP 最大 50 并发连接
    }
}

静态资源缓存优化,较少后端请求

location ~* /zentao/(css|js|images|fonts)/ {
    proxy_pass http://172.16.50.80;
    proxy_cache zentao_cache;  # 定义缓存区
    proxy_cache_valid 200 304 8h;  # 缓存 8 小时
    proxy_cache_valid any 1m;  # 非 200/304 缓存 1 分钟
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    add_header X-Proxy-Cache $upstream_cache_status;  # 响应头显示缓存状态(HIT/MISS)
}

健康检查与自动恢复

通过 ngx_http_proxy_module 配置后端服务健康检查,避免请求转发到故障节点:

location /zentao/ {
    proxy_pass http://172.16.50.80/zentao/;
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;  # 失败时自动切换备用节点(需配合 upstream)
    proxy_connect_timeout 3s;  # 连接超时 3 秒
    proxy_read_timeout 10s;  # 读取超时 10 秒
}

日志与监控

  • 访问日志:配置详细日志格式,记录请求来源、URL、状态码、响应时间,便于故障排查:
  log_format main '$remote_addr [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time';
  access_log /var/log/nginx/zentao_access.log main;  # 禅道访问日志