Skip to content

常见FAQ解答

本章节收集了在使用GenieOS过程中常见的问题和解答,帮助您快速解决可能遇到的困难。

开发相关问题

关于魔方外网域名与办公网域名的相关问题释义

常见端口讲解

端口服务描述
8080nginx业务端口,静态文件服务+接口转发
8301nginx -> gatewayAPI网关的https端口
8001nacos注册中心+配置中心
9092kafka
8411Keycloak认证中心、用户管理中心

接口地址

  • 魔方网络下,网关地址是https://172.16.0.3:8301
  • 办公网的网络下进行调测,网关地址:https://{办公网wan口ip}:8301
  • 其他网络下调测,已交付项目不支持,只有交付中的项目,可以申请域名地址去调测。

网关路由的一些规则

  • 网关的默认配置是开启了服务自发现功能

    yaml
    spring:
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true
              lower-case-service-id: true

    Spring Cloud Gateway会自动为注册到服务发现组件的每个服务创建路由规则。默认情况下,路由路径与服务ID对应(可通过lowerCaseServiceId控制大小写),并使用负载均衡(lb://)将请求转发到相应的服务实例。

    如果您的服务名为TEST11注册到Nacos,根据以上配置,Spring Cloud Gateway会自动生成以下路由规则:

    • 路由ID:自动生成,通常是一个唯一标识符
    • 目标URIlb://TEST11(使用服务名构建负载均衡URI)
    • 路径谓词/test11/**(由于lower-case-service-id: true,所以路径是小写的)
    • 过滤器:会自动添加一个StripPrefix=1的过滤器,移除路径中的第一段(即服务名部分)
  • 如果使用8080端口或者包含dfs关键字的域名请求访问api接口,需要加上**/factory/v1/**的前缀

    因为8080端口是nginx的监听端口,默认会配置一个路由规则如果匹配到**/factory/v1/** 的请求会转发到8301网关地址

  • 如果基于apifox客户端调测open接口,可以使用下面的脚本作为前置操作,自动生成ak/sk的认证请求头

    javascript
    // eslint-disable-next-line no-extend-native
    
    var cryptoJs = require('crypto-js')
    
    function encode(str) {
        var result = encodeURIComponent(str)
    
        return result.replace(/!/g, '%21')
            .replace(/'/g, '%27')
            .replace(/\(/g, '%28')
            .replace(/\)/g, '%29')
            .replace(/\*/g, '%2A')
    }
    
    Date.prototype.format = function(fmt) {
        var o = {
            'M+': this.getMonth() + 1, // 月份
            'd+': this.getDate(), // 日
            'h+': this.getHours() - 8, // 小时
            'm+': this.getMinutes(), // 分
            's+': this.getSeconds(), // 秒
            'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
            'S': this.getMilliseconds() // 毫秒
        }
        if (/(y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
        }
        for (var k in o) {
            if (new RegExp('(' + k + ')').test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
            }
        }
        return fmt
    }
    
    var myDate = new Date()
    var ti = myDate.format('yyyy-MM-ddThh:mm:ssZ')
    const accessKeyId = pm.environment.get('AccessKeyId')
    const accessKeySecret = pm.environment.get('AccessKeySecret')
    const signatureNonce = '22'
    const method = pm.request.method
    // 存放所有需要用来签名的参数
    const param = {'AccessKeyId': accessKeyId, "Timestamp": ti, "SignatureNonce": signatureNonce}
    // 加入 query 参数
    const queryParams = pm.request.url.query
    
    queryParams.each(item => {
        if (!item.disabled && item.value !== '') { // 启用且非空参数值的参数才参与签名
            param[item.key] = item.value
        }
    })
    
    // 取 key
    const keys = []
    for (const key in param) {
        keys.push(key);
    }
    // 参数名 ASCII 码从小到大排序(字典序)
    keys.sort()
    // 转成键值对
    const paramPair = []
    for (let i = 0, len = keys.length; i < len; i++) {
        const k = keys[i]
        paramPair.push(k + '=' + encodeURIComponent(param[k])) // urlencode 编码
    }
    // 拼接
    const stringSignTemp = paramPair.join('&')
    // console.log(stringSignTemp);
    
    const geneStr = (method + '&' + encode('/') + '&' + encode(stringSignTemp)).replace('/', '%2F')
    console.log('genStr:     ' + geneStr)
    const signStr = cryptoJs.HmacSHA1(geneStr, accessKeySecret + "&")
    var sign = cryptoJs.enc.Base64.stringify(signStr)
    if (method !== 'POST') {
        console.log("不是POST请求")
        sign = encodeURIComponent(sign)
    }
    // 方案一:直接修改接口请求的 query 参数,注入 sign,无需使用环境变量。
    // 参考文档:https://www.apifox.cn/help/app/scripts/examples/request-handle/
    pm.request.headers.add({ key: 'Timestamp', value: ti })
    pm.request.headers.add({ key: 'Signature', value: sign })
    pm.request.headers.add({ key: 'AccessKeyId', value: accessKeyId })
    pm.request.headers.add({ key: 'SignatureNonce', value: signatureNonce })

    image-20250523114701086

    image-20250523114743407

  • 如果是内网ip调用接口时,需要注意忽略证书检测,魔方内的网关地址默认是https的方式,并且是自签名证书,客户端需要配置忽略证书检测。

Kafka 异常问题

办公网段连接 Kafka

默认配置只面向魔方内网客户端。如果办公网客户端需要直连 Kafka,需要为 Kafka 增加一个办公网可访问的监听地址。

以下示例适用于单节点、ZooKeeper 模式的 Kafka 2.8.1:

yaml
  kafka:
    image: swr.cn-south-1.myhuaweicloud.com/yelink_iot/kafka:2.8.1
    container_name: kafka
    restart: always
    ports:
      - "9092:9092" # 魔方内网访问
      - "9093:9093" # 办公网访问
    environment:
      KAFKA_LISTENERS: INTERNAL://0.0.0.0:9092,EXTERNAL://0.0.0.0:9093
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://${LOCAL_IP}:9092,EXTERNAL://192.168.2.148:9093
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_JMX_OPTS: "-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=${LOCAL_IP}"
      KAFKA_NUM_PARTITIONS: 3
      KAFKA_LOG_CLEANUP_POLICY: delete
      KAFKA_LOG_RETENTION_BYTES: 10737418240
      KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS: 60000
      KAFKA_BROKER_ID: 1

配置说明:

  1. KAFKA_LISTENERS 是 Kafka 在容器内实际监听的地址。
  2. KAFKA_ADVERTISED_LISTENERS 是 Kafka 返回给客户端的连接地址,办公网客户端必须能访问 EXTERNAL 对应的 IP 和端口。
  3. KAFKA_LISTENER_SECURITY_PROTOCOL_MAP 用于声明每个 listener 使用的安全协议,本示例仍使用明文 PLAINTEXT
  4. KAFKA_INTER_BROKER_LISTENER_NAME 指定 broker 内部通信使用 INTERNAL,避免内部通信走办公网入口。

修改时注意:

  • ${LOCAL_IP} 需要是 Kafka 所在主机的魔方内网 IP。
  • 192.168.2.148 需要替换为办公网可访问的魔方路由器 WAN 口 IP。
  • 办公网到 Kafka 主机的 9093 端口需要网络放通。
  • 办公网客户端连接地址使用 192.168.2.148:9093
  • 多节点 Kafka 不能直接复用这个单节点示例,每个 broker 的 advertised.listeners 都必须使用各自可达的地址。

基于 MIT 许可发布