关于OA自定义接口不能解析汉字记录

项目场景:

上一篇文章介绍了如何在泛微OA上传自定义class接口文档实现接口开放 相关链接

泛微OA自定义接口,将生成的class文件压缩包在 /weaver路径下解压,实现壳子功能。该接口接收任意格式的请求报文,传输到cmd层(转base64),调用相关ESB事件后在ESB中实现对相关报文解析(base64转码)后,调用OA内部相关方法实现对开放API的自由接收报文需求。


问题描述

请求报文含有中文字符,接口解析后变乱码。

在ESB中直接输入报文base64转码没有乱码,从postman发送请求返回乱码

"eknam": "������ҵ��_�����ɹ���1",


原因分析:

从postman-OA服务器中间件-接口代码依次分析

1.接口代码解析优化

postman使用raw方式传输请求体,初步确认是UTF-8格式,在接口的代码层,优化相关请求request数据流 ,相关代码如下:

java 复制代码
package com.engine.free.web;
import com.engine.common.util.ParamUtil;
import com.engine.common.util.ServiceUtil;

import com.engine.free.service.MM017ReciveDataService;
import com.engine.free.service.impl.MM017ReciveDataServiceImpl;
import net.sf.json.JSONObject;
import weaver.general.BaseBean;
import weaver.hrm.HrmUserVarify;
import weaver.hrm.User;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class MM017EngineAction {
   public MM017EngineAction(){}
   BaseBean baseBean =  new BaseBean();
    /**
     * 自定义getService 方法,ServiceUtil对象getService方法获取自定义service对象
     * @param request
     * @param response
     * @return
     */
    private MM017ReciveDataService getService(HttpServletRequest request, HttpServletResponse response) {
        User user = HrmUserVarify.getUser(request, response);
        return (MM017ReciveDataServiceImpl) ServiceUtil.getService(MM017ReciveDataServiceImpl.class, user);
    }

@POST
@Path("/SchemaService")
@Produces(MediaType.APPLICATION_JSON)
public  String SchemaService(@Context HttpServletRequest request, @Context HttpServletResponse response) throws UnsupportedEncodingException {
    Map<String,Object> apidatas = new HashMap<>();
    baseBean.writeLog("CharacterEncoding: " + request.getCharacterEncoding());
    baseBean.writeLog("file.encoding: " + System.getProperty("file.encoding"));
    Map map = ParamUtil.request2Map(request);
    try {
        User user = HrmUserVarify.getUser(request, response);

        InputStream is =  request.getInputStream();
        String jsonStr = inputStream2StringNew(is,request);
        baseBean.writeLog("MM017 EngineAction jsonStr = " + jsonStr);
        map.put("json", jsonStr);

        apidatas = this.getService(request, response).SchemaService(user,map);
    } catch (IOException exception) {
        exception.printStackTrace();
        ((Map)apidatas).put("api_status", false);
        ((Map)apidatas).put("api_errormsg", "catch Exception: " + exception.getMessage());
        baseBean.writeLog("ERRO api_status: "+apidatas.get("api_status"));
        throw new RuntimeException(exception);
    }

    return ((Map)apidatas).get("result").toString();
}

/*
    public static String inputStream2StringNew(InputStream is) {
        try {
            ByteArrayOutputStream boa = new ByteArrayOutputStream();
            int len ;
            byte[] buffer = new byte[1024];


            while((len = is.read(buffer)) != -1) {
                boa.write(buffer, 0, len);
            }

            is.close();
            boa.close();
            byte[] result = boa.toByteArray();
            String temp = new String(result);
            if (temp.contains("utf-8")) {
                return new String(result, "utf-8");
            } else {
                return temp.contains("gb2312") ? new String(result, "gb2312") : new String(result, "utf-8");
            }
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }
    }
*/

    public static String inputStream2StringNew(InputStream is, HttpServletRequest request) {
        try {
            // 1. 优先从Content-Type获取编码,如:application/json; charset=utf-8
            String charset = request.getCharacterEncoding();
            if (charset == null || charset.isEmpty()) {
                charset = StandardCharsets.UTF_8.name(); // 默认UTF-8
            }

            // 2. 直接用正确编码一次性解码
            ByteArrayOutputStream boa = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                boa.write(buffer, 0, len);
            }

            return boa.toString(charset);  // 直接用指定编码解码

        } catch (IOException e) {
            throw new RuntimeException("读取请求体失败", e);
        }
    }
}

入口方法实现指定使用utf-8解码

结果还是乱码

2. tcpdump抓包排查

在安装了tcpdump的服务器上,运行tcpdump应用后使用postman发送请求抓包,ctrl+c结束

bash 复制代码
tcpdump -i any -s 0 -w /app/weaver/postman_to_bes.pcap 'port 8080 and host 172.19.*.*'

其中172.19.*.*'是我本地postman所在主机ip。执行以下命令查看请求报文

bash 复制代码
  tcpdump -r /app/weaver/postman_to_bes.pcap -X -nn 'port 8080'
  • -r:读取指定的 pcap 文件。
  • -A:以 ASCII 码的形式打印出数据包的内容(这样你就能看到 HTTP 请求和响应的具体文本了)。
  • -nn:直接把 IP 和端口号显示出来,不进行域名解析,阅读起来更清晰。

效果如下:

root@localhost weaver\]# tcpdump -r /app/weaver/postman_to_bes.pcap -X -nn 'port 8080' reading from file /app/weaver/postman_to_bes.pcap, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 Warning: interface names might be incorrect dropped privs to tcpdump 10:56:53.250860 enp18s0 In IP 172.19.\*.\*.51492 \> 192.168.32.44.8080: Flags \[S\], seq 2620177529, win 64240, options \[mss 1460,nop,wscale 8,nop,nop,sackOK\], length 0 0x0000: 4500 0034 538b 4000 7c06 1364 ac13 0aed E..4S.@.\|..d.... 0x0010: c0a8 202c c924 1f90 9c2c bc79 0000 0000 ...,.$...,.y.... 0x0020: 8002 faf0 9aef 0000 0204 05b4 0103 0308 ................ 0x0030: 0101 0402 .... 10:56:53.250931 enp18s0 Out IP 192.168.32.44.8080 \> 172.19.10.237.51492: Flags \[S.\], seq 720001401, ack 2620177530, win 64240, options \[mss 1460,nop,nop,sackOK,nop,wscale 10\], length 0 0x0000: 4500 0034 0000 4000 4006 a2ef c0a8 202c E..4..@.@......, 0x0010: ac13 0aed 1f90 c924 2aea 5979 9c2c bc7a .......$\*.Yy.,.z 0x0020: 8012 faf0 97fb 0000 0204 05b4 0101 0402 ................ 0x0030: 0103 030a ....

将以上所有内容丢给AI后返回结论:Postman 发送的是正确的 UTF-8!

| 字段 | 抓包原始字节 | UTF-8 解码结果 |

| ----------- | ------------------------------------- | ------------------- |

| `name_org1` | `E7 A6 8F E8 80 80 E7 8E BB E7 92 83` | **福耀玻璃** ✅ |

| `eknam` | `E5 9B BD E9 99 85...` | **国际事业部\_备件采购组1** ✅ |

| `txz01` | `33 2F 34 E6 A1 A3 E5 8F 8C...` | **3/4档双锥环组件** ✅ |

截图分析

1. 左侧:协议解析树

Wireshark 已经自动识别并解析了 JSON 结构:

  • JavaScript Object Notation: application/json

  • Member: bodyObjectMember: ebeln

这说明 Wireshark 认为这是一个合法的 JSON ,并且 Content-Type 是 application/json没有 charset 声明)。

2. 右侧:原始字节视图(关键!)

name_org1 字段对应的字节区域:

plain

复制

复制代码
0510: ... 22 6e 61 6d 65 5f 6f 72 67 31 22 3a 20 22 e7 a6 8f  "name_org1": "..
0520: e8 80 80 e7 8e bb e7 92 83 22 2c 0d 0a 20 20 20 20 22  .......",....    "

name_org1 的值字节E7 A6 8F E8 80 80 E7 8E BB E7 92 83

这是 UTF-8 编码 ,解码为:福耀玻璃

表格

字段 原始字节 编码 内容
name_org1 E7A68F E88080 E78EBB E79283 UTF-8 福耀玻璃
ebeln 34353030303030323932 ASCII 4500000292 ✅

Wireshark 的 JSON 解析器能正确显示中文,说明网络层的 UTF-8 字节完全正确

3.最可能的原因:JVM file.encoding=GBK

Postman → 网络 → 宝兰德

这里的字节是正确的 UTF-8

根因确认 :字节到达宝兰德后,JVM 用 file.encoding=GBK 处理 UTF-8 字节,导致乱码。

修改宝兰德conf目录下server.config文件,

<jvm-options>-Dfile.encoding=GBK</jvm-options>改为

<jvm-options>-Dfile.encoding=UTF-8</jvm-options>

重启测试,不在是乱码,但是不建议这么做!!!


解决方案:

以上第三点确认可以实现接收中文报文,但是泛微厂商不建议这样改,因为如果修改这项配置,重启服务后,如果之前使用GBK读的jsp文件通过UTF-8变为乱码,就会不可逆的乱码!!!

相关推荐
ch.ju10 小时前
Java Programming Chapter 4——Composition of objects
java·开发语言
无聊的老谢10 小时前
编译期即正义:利用 Java Lambda 构建类型安全的 SQL 表达式引擎
java·开发语言
疯狂成瘾者10 小时前
Elasticsearch 是什么?它和普通数据库查询有什么区别?
java
运维行者_10 小时前
ITOps自动化:全面解析
java·服务器·开发语言·网络·云计算
Chase_______10 小时前
【Java杂项】为什么 b += 1 可以,但 b = b + 1 会报错?类型提升与复合赋值详解
java·开发语言·python
勿忘,瞬间10 小时前
Spring日志
java·spring boot·spring
AI人工智能+电脑小能手10 小时前
【大白话说Java面试题 第62题】【JVM篇】第22题:怎么查看服务器默认的垃圾回收器是哪一个?
java·服务器·jvm·面试
yqzyy10 小时前
C#如何优雅处理引用类型的深拷贝(十一)
java·网络·nginx
范什么特西10 小时前
idea里面jsp找不到图片
java·开发语言·servlet