之前有这样一个问题。
responseBody from :{"data":{"payerId":"1952298788269985793","payerName":"刘一","payerType":"INDIVIDUAL","payerIdType":"ID_CARD","payerIdNo":"41xxx","status":"REJECT","failReason":"审核不通过:其他原因有误","createTime":"2025-08-04T09:21:18.000Z","modifyTime":"2025-08-04T09:21:18.000Z"},"code":"000000"} 10.0.0.105 2025-08-04 17:21:18,326 [http-nio-8003-exec-7] ERROR [m.g.modules.mybatis.controller.OrderController] OrderController.java:155 - error when call lianlian me.guanglian.exception.LianlianRequestException: 调用接口失败(返回的数据,签名验证不通过)。请求URL:/outbound/card/v1/payer响应内容:{"data":{"payerId":"1952298788269985793","payerName":"刘一","payerType":"INDIVIDUAL","payerIdType":"ID_CARD","payerIdNo":"41xxx","status":"REJECT","failReason":"审核不通过:其他原因有误","createTime":"2025-08-04T09:21:18.000Z","modifyTime":"2025-08-04T09:21:18.000Z"},"code":"000000"}现在我切换成了当时出错的docker镜像,同样的请求,竟然不报验签失败了。
responseBody from :{"data":{"payerId":"1991772843112796161","payerName":"刘41xxx","payerType":"INDIVIDUAL","payerIdType":"ID_CARD","payerIdNo":"41xxx","status":"REJECT","failReason":"审核不通过:其他原因有误","createTime":"2025-11-21T07:37:06.000Z","modifyTime":"2025-11-21T07:37:06.000Z"},"code":"000000"} 10.0.0.105 2025-11-21 15:37:06,000 [http-nio-8003-exec-7] INFO [5f24b835c4724fd2ae6b3ae2a48ef066/e23c43427593d899]这是出错时的dockerfile
# can not use jstack in this base image
FROM openjdk:8u322-jdk-bullseye
ENV LANG="en_US.UTF-8"
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /data/app
COPY /target/st-remit.jar /data/app/st-remit-8003.jar
COPY target/classes/skywalking /data/app/agent
ENTRYPOINT ["/entrypoint"]
EXPOSE 8003
ENTRYPOINT ["java","-jar","-Dcom.sun.jndi.rmi.object.trustURLCodebase=false", "-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false","/data/app/st-remit-8003.jar","--spring.profiles.active"]而使用如下就能正常
FROM openjdk:8u322-jdk-bullseye
ENV LANG="C.UTF-8"
ENV TZ=Asia/Shanghai
# 设置时区 + 安装字体(DejaVu Font)
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
&& apt-get update \
&& apt-get install -y --no-install-recommends fonts-dejavu fontconfig \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /data/app
COPY /target/st-remit.jar /data/app/st-remit-8003.jar
#COPY target/classes/skywalking /data/app/agent
ENTRYPOINT ["java","-jar","-Dcom.sun.jndi.rmi.object.trustURLCodebase=false", "-Dcom.sun.jndi.cosnaming.object.trustURLCodebase=false","/data/app/st-remit-8003.jar"]
CMD ["--spring.profiles.active=prod"]
EXPOSE 8003解释一下原因
你的旧 Dockerfile 会导致 验签所依赖的 JSON 串序列化格式不同(尤其是末尾的空格、行尾换行、编码等),从而导致验签失败;
而新 Dockerfile 环境(locale、字体、依赖库)让 JVM 使用了 不同的默认 Charset/Locale,从而使序列化结果一致,因此签名验证自然不再失败。
换句话说:
你的业务代码没变,变的是 Docker 镜像的系统环境,导致 JVM 的默认字符集、Locale、JSON 输出格式发生了改变 → 直接影响验签。
差异 1: Locale 不同(这是最核心的)
旧版本 Dockerfile
ENV LANG=”en_US.UTF-8”
新版本 Dockerfile
ENV LANG=”C.UTF-8”
| Locale | 影响 |
|---|---|
| en_US.UTF-8 | 使用较完整的 UTF-8 处理,但受系统 locale 配置影响,有时会自动格式化数字、日期、字符串排序方式不同 |
| C.UTF-8(POSIX) | 严格稳定,不会根据地区改变格式,是 Docker 默认最可控、最可预测的 locale |
支付的验签算法 对原文串要求极高:
换行
空格
字符顺序
UTF-8 编码
Unicode 归一化
任意一点不同,都导致签名不一致。
你旧镜像的 en_US.UTF-8 在某些系统里会自动进行:
Unicode normalization(NFC → NFD 或反之)
JSON 字符串的排序变化
数字/日期/小数点本地化
特殊字符自动替换
⚠️ 这些都会让“签名原文串”发生微小差异,导致验签失败。
而 C.UTF-8 是 Docker 中最稳定的 UTF-8,不会乱动内容,因此不再验签失败。
作者:张三 创建时间:2025-11-21 16:23
最后编辑:张三 更新时间:2025-11-28 13:34
最后编辑:张三 更新时间:2025-11-28 13:34