ai之对接电信ds后端服务,通过nginx代理转发https为http,对外请求,保持到达第三方后请求头不变

前置环境:

  • 在微信小程序中嵌入H5页面(智能客服),需要让h5页面在https的域名服务器上。即通过 nginx 部署成web服务,还得配置域名和端口443访问。
  • 电信的第三方deepseek服务 ,只接收http请求,暂未支持https请求。
  • 所以我们要使用https的话 就需要在智文网关xxx:31170前面 自行加一个网关进行处理(https -> http)。

下面配置nginx 代理,及调试。主要麻烦在了我方与第三方签名验证不通过上 (postJsonWithAuth)。

1. 构建请求头的方法

1.1

public class SignUtils 工具类

//    public static final String PARAM_HEADER_DATE = "Date";public static final String PARAM_HEADER_X_DATE = "x-date";private static final List<String> SIGNED_HEADERS = new ArrayList<>();private static final String algorithm = "HmacSHA256";private static final String hmacAlgorithm = "hmac-sha256";static {SIGNED_HEADERS.add("x-tenantid");SIGNED_HEADERS.add("x-userid");SIGNED_HEADERS.add("x-source");}
1.2
private static Map<String, String> buildHeaders() {Map<String, String> headers = new HashMap<>();headers.put("Content-Type", "application/json");headers.put("x-userid", RequestParam.getUserId());headers.put("x-tenantid", RequestParam.getTenantId());headers.put("x-source", RequestParam.getSource());LocalDateTime utcTime = LocalDateTime.now(ZoneOffset.UTC);// 定义日期时间格式DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);// 格式化时间并输出String formattedUtcTime = utcTime.format(formatter);headers.put(SignUtils.PARAM_HEADER_X_DATE, formattedUtcTime);return headers;}
1.3

/**
API 常量类
**/
public class ApiConstants

// 对话接口: 智文-SSE对话接口public static final String CHAT_OPENAPI = "/ais/bot/openapi/dcc/sseDialog";// 智文-同步对话接口public static final String CHAT_OPENAPI_SYNC = "/ais/bot/openapi/dcc/dialog";// 数科官网本地https 转发public static final String API_DIANXIN_PROXY = "/apidx";public static final String CHAT_OPENAPI_SYNC_PROXY = API_DIANXIN_PROXY + CHAT_OPENAPI_SYNC;

在这里插入图片描述

主要问题就忽略了 我们签名时,参数uri 加了"/api" 前缀,通过nginx 代理转发后,过滤了 /api 前缀,到达第三方后,对方用的原始 uri验签,所以总是不通过。

过程中 在ds这台服务器上装了 tcpdump 抓包工具,比对本地debug(不代理)成功的报文,和访问https生产服务器 nginx代理失败的报文

在这里插入图片描述

在这里插入图片描述

/*** @param api 第三方接口uri* @param reqBody post请求体参数*/public static String postJsonWithAuth(String api, String reqBody) throws Exception {
//        String url = RequestParam.getHost() + api;// 通过nginx 代理转发时,加上前缀 String url = RequestParam.getHost() + ApiConstants.API_DIANXIN_PROXY + api;long startTime = System.currentTimeMillis();try {Map<String, String> headers = buildHeaders();// 签名时,与第三方保持一致,使用原始api不变 ,不使用代理后的apiString sign = SignUtils.generateAuth(RequestParam.getAccessKey(), RequestParam.getSecretKey(),"POST", api, headers, new HashMap<>(), reqBody);headers.put("Authorization", sign);// 请求开始监控log.info(">>>> HTTP请求开始 [URL: {},API: {}]", url, api);log.info(">>>> HTTP请求头: {}", headers);log.info(">>>> HTTP请求参数 [Body: {}]", reqBody);RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), reqBody);Request request = new Request.Builder().url(url).headers(Headers.of(headers)).post(requestBody).build();try (Response response = httpClient.newCall(request).execute()) {String responseBody = response.body().string();log.info("<<<< 原始响应结果:[状态码: {}, 内容: {}]", response.code(), response);if (response.isSuccessful()) {return responseBody;} else {log.error("详细错误响应: {}", responseBody);throw new IOException("HTTP请求失败: " + response.code() + " - " + response.message());}}} catch (Exception e) {long cost = System.currentTimeMillis() - startTime;log.error("<<<< 请求异常 [耗时: {} ms, URL: {}, 错误: {}]", cost, url, e.getMessage(), e);throw e;} finally {long totalCost = System.currentTimeMillis() - startTime;log.info("==== 请求结束 [总耗时: {} ms] ====", totalCost);}}

测试方法:

@Test(timeOut = 60000)public void testSSEChat() throws Exception {String question="石家庄有什么好玩的";
//        String agentCode = queryAgentCode();String agentCode = "agent1048486107377569792";String messageId = UUID.randomUUID().toString();String sessionId = UUID.randomUUID().toString();String userId = RequestParam.getUserId();MessageRequest messageRequest = new MessageRequest();messageRequest.setMessageId(messageId);messageRequest.setSessionId(sessionId);messageRequest.setMsgType("TEXT");messageRequest.setUserId(userId);messageRequest.setContent(question);messageRequest.setQuery(question);messageRequest.setAgentCode(agentCode);messageRequest.setTest(1);messageRequest.setChatType("chat");messageRequest.setRequestTime(System.currentTimeMillis());messageRequest.setEntry("default");// 添加extraData参数Map<String, Object> extraData = new HashMap<>();Map<String, Object> filterMap = new HashMap<>();filterMap.put("knowledgeFilters", Collections.singletonList(Collections.singletonMap("knowledgeBaseCode", "1050656046175358976")));extraData.put("filter", JsonUtil.toJSONString(filterMap));extraData.put("range", "all");messageRequest.setExtraData(extraData);CountDownLatch latch = new CountDownLatch(5);AtomicBoolean received = new AtomicBoolean(false);String resp = OkHttpUtils.postJsonWithAuth(ApiConstants.CHAT_OPENAPI_SYNC, JsonUtil.toJSONString(messageRequest));log.info("同步结果: {}", resp);Thread.sleep(10000);   }

下面是Nginx配置:

# 添加详细日志记录
log_format proxy_debug '$remote_addr - $remote_user [$time_local] ''"$request" $status $body_bytes_sent ''"$http_referer" "$http_user_agent" ''Authorization: "$http_authorization" ''x-source: "$http_x_source" ''x-userid: "$http_x_userid" ''x-tenantid: "$http_x_tenantid" ''x-date: "$http_x_date" ''content-type: "$http_content_type" ''cookie_header: "$http_cookie" ''host_header: "$host"';server {listen       443 ssl;charset   utf-8;server_name stdai.sjzwltszkj.com ;ssl_certificate      /usr/local/nginx/conf/cert/cert.pem;ssl_certificate_key  /usr/local/nginx/conf/cert/cert.key;ssl_session_cache    shared:SSL:1m;ssl_session_timeout  5m;#charset koi8-r;#access_log  logs/host.access.log  main;# location / {location ~* \.txt$ {root /data/std/authentication;}location /ai/ {alias /www/wwwroot/static.ltkj.com/std_applet/dist/build/h5/ ;#root /www/wwwroot/static.ltkj.com/std_applet/h5/dist/;try_files $uri $uri/ /ai/index.html;index  index.html index.htm;}location /static/ {alias /www/wwwroot/static.ltkj.com/std_applet/dist/build/h5/static/;expires 1y;add_header Cache-Control "public";}# API代理 关键配置location /apidx/ {# 1. 保持原始HTTP版本和连接行为proxy_http_version 1.1;proxy_set_header Connection "";# 2. 保持原始Host头proxy_set_header Host $proxy_host;proxy_set_header x-forwarded-host $host;# 传递所有头并保持原始顺序proxy_pass_request_headers on;# 3. 禁用不必要的头传递proxy_pass_header Server;proxy_pass_header Date;proxy_hide_header 'Access-Control-Allow-Origin';proxy_hide_header 'Access-Control-Allow-Methods';proxy_hide_header 'Access-Control-Allow-Headers';# 4. 精确传递鉴权相关头proxy_set_header Authorization $http_authorization;proxy_set_header x-source $http_x_source;proxy_set_header x-userid $http_x_userid;proxy_set_header x-tenantid $http_x_tenantid;proxy_set_header x-date $http_x_date;# 5. 代理到后端服务器 https -> http. 过滤掉/api/ 后保持原始请求路径proxy_pass http://222.223.xxx.xxx:xxx70/;# 超时设置proxy_connect_timeout 60s;proxy_send_timeout 60s;proxy_read_timeout 60s;# 禁用缓冲proxy_buffering off;# CORS配置add_header 'Access-Control-Allow-Origin' 'https://stdai.sjzwltszkj.com' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With, X-CSRF-Token, x-source, x-userid, x-tenantid, x-date' always;add_header 'Access-Control-Allow-Credentials' 'true' always;add_header 'Access-Control-Expose-Headers' 'Authorization' always;# 处理OPTIONS预检请求if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' 'https://stdai.sjzwltszkj.com' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-CSRF-Token,x-source,x-userid,x-tenantid,x-date' always;add_header 'Access-Control-Max-Age' 1728000 always;add_header 'Content-Type' 'text/plain; charset=utf-8' always;add_header 'Content-Type' 'text/plain; charset=utf-8' always;add_header 'Content-Length' 0 always;return 204;}}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}access_log /usr/local/nginx/logs/access.log proxy_debug ;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/88080.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/88080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第十四节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Flask 后端 生产部署讲解

Vben5 系列文章目录 💻 基础篇 ✅ 第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 ✅ 第二节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门 - Python Flask 后端开发详解(附源码) ✅ 第三节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

Unity开发如何解决iOS闪退问题

一、iOS闪退常见原因及排查方法1. 内存问题&#xff08;最常见原因&#xff09; 症状表现&#xff1a; 设备发热后闪退 加载大型场景时崩溃 控制台出现EXC_RESOURCE RESOURCE_TYPE_MEMORY日志 解决方案&#xff1a; // 内存监控代码 void Update() { Debug.Log($"内存使用…

【机器学习笔记 Ⅲ】5 强化学习

强化学习&#xff08;Reinforcement Learning, RL&#xff09; 强化学习是机器学习的一个分支&#xff0c;其核心思想是让智能体&#xff08;Agent&#xff09;通过与环境&#xff08;Environment&#xff09;的交互学习最优策略&#xff08;Policy&#xff09;&#xff0c;以最…

pytorch深度学习-卷积神经网络CNN-MNIST-gpu加速

一、为什么需要 CNN&#xff1f;从图像识别的 “麻烦” 说起假设你想让电脑识别一张图片里有没有猫。 如果用传统神经网络&#xff1a;一张 100100 的彩色图片&#xff0c;有 100100330000 个像素点&#xff0c;每个像素点都是一个输入神经元。传统网络需要每个输入神经元和隐藏…

【阿里巴巴JAVA开发手册】IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式。

问题&#xff1a;当使用 IDEA SSH 远程开发时&#xff0c;SFTP 同步的 Windows 本地编辑的 config/plugin_config 文件文本内容中 “换行符”与 Unix、Linux 的文件文本内容换行符字符集不一致&#xff0c;导致 docker 容器中自定义 /opt/seatunnel/bin/install_plugin 在执行以…

自动驾驶ROS2应用技术详解

自动驾驶ROS2应用技术详解 目录 自动驾驶ROS2节点工作流程自动驾驶感知融合技术详解多传感器数据同步技术详解ROS2多节点协作与自动驾驶系统最小节点集 1. 自动驾驶ROS2节点工作流程 1.1 感知输出Topic的后续处理 在自动驾驶系统中&#xff0c;感知节点输出的各种Topic会被…

Redis底层实现原理之订阅发布机制

文章目录1. 通知类型2. 实现原理2.1 Pub/Sub2.1.1 基础知识点2.1.2 频道和订阅者的存储通知原理2.1.3 键空间通知2.1.4 客户端消费2.1.5 缺陷2.2 Redis Stream2.2.1 基础知识点2.2.2 基础数据结构2.2.3 消费者组管理2.2.4 消息和消费者持久化2.2.5 消息生产和消费2.2.6 消费者拉…

【MATLAB代码】AOA与TDOA混合定位例程,自适应基站数量,二维,可调节锚点数量。订阅专栏后,可直接查看matlab源代码

本文给出一个matlab代码,用于在二维平面上,使用AOA的角度测量和TDOA的到达时间差的测量,来达到对未知点的精确定位。最后输出定位示意图、真实点坐标、仅AOA定位坐标与误差、仅TDOA定位的坐标与误差、AOA+TDOA混合定位的坐标与误差。订阅专栏后可直接查看源代码,粘贴到MATL…

Node.js 所有主要版本的发布时间、稳定版本(Stable)和长期支持版本(LTS) 的整理

以下是 Node.js 所有主要版本的发布时间、稳定版本&#xff08;Stable&#xff09;和长期支持版本&#xff08;LTS&#xff09; 的整理&#xff0c;涵盖从早期版本到当前最新版本的信息。 &#x1f4c5; Node.js 版本发布规律 每 6 个月发布一个新主版本&#xff08;偶数月&am…

【牛客刷题】小红的v三元组

文章目录 一、题目介绍1.1 题目描述1.2 输入描述1.3 输出描述1.4 示例二、解题思路2.1 核心算法设计2.2 性能优化关键2.3 算法流程图三、算法实现四、算法分析4.1 时间复杂度4.2 空间复杂度4.3 正确性证明五、为什么选择离散化+树状数组的解法?5.1 问题本质分析5.2 解法设计思…

c语言学习_函数递归

今天学习函数递归。函数递归通俗来说就是函数自己调用自己&#xff0c;递归的主要思考方式在于&#xff1a;把大事化小。例子&#xff1a;接受一个整型值&#xff0c;按照顺序打印它的每一位。void print(unsigned int n) {if (n > 9){print(n / 10);}printf("%d"…

Bash与Zsh与Fish:在Linux中你应该使用哪个Shell

命令行 shell 是与操作系统交互的重要工具&#xff0c;使用户能够高效地执行命令、自动化任务和运行脚本。 虽然有各种外壳选项可供选择&#xff0c;但Bash、Zsh和Fish作为最受欢迎的选择脱颖而出&#xff0c;每种都提供独特的功能&#xff0c;因此理解它们的差异对于选择适合…

Peek-Ubuntu上Gif录制工具-24.04LTS可装

安装方法&#xff08;Ubuntu24.04.2LTS测试通过&#xff09; sudo apt update sudo apt install peek纯无语&#xff0c;&#x1f9df; 一个软件&#xff0c;仨网站&#xff0c;四份重复的教程&#xff1a; 添加 PPA更新源报错&#xff08;不支持 noble&#xff09;搜到 4 篇教…

DVWA靶场通关笔记-验证码绕过reCAPTCHA(High级别)

目录 一、reCAPTCHA 二、代码审计&#xff08;High级别&#xff09; 1、渗透准备 &#xff08;1&#xff09;配置security为High级别。 &#xff08;2&#xff09;配置RECAPTCHA参数 &#xff08;3&#xff09;再次打开靶场 2、源码分析 &#xff08;1&#xff09;inde…

【Java安全】RMI基础

文章目录介绍实现服务端 Server客户端 Client通信过程数据端与注册中心(1099 端口)建立通讯客户端与服务端建立 TCP 通讯客户端序列化传输 调用函数的输入参数至服务端总结介绍 RMI 全称 Remote Method Invocation&#xff08;远程方法调用&#xff09;&#xff0c;即在一个 J…

MySQL索引面试问题梳理

本文系统剖析MySQL索引的核心机制&#xff1a; ‌索引分类全景图‌&#xff1a;详解聚簇/非聚簇索引的逻辑差异与物理存储特点‌B树的统治性优势‌&#xff1a;通过对比Hash/B树揭示InnoDB的底层选择逻辑 一、索引分类的常见困惑解析 1. 按物理存储分类 类型 存储内容 数量限…

SSH密钥 与 Ed25519密钥 是什么关系

SSH 密钥与 Ed25519 密钥的关系可以从技术实现和应用场景两个角度理解。简而言之&#xff1a;Ed25519 密钥是 SSH 密钥的一种类型&#xff0c;用于在 SSH 协议中实现安全认证。以下是详细解释&#xff1a; 1. SSH 密钥的通用概念 SSH&#xff08;Secure Shell&#xff09;是一…

【PyTorch 当前版本不支持 NVIDIA GeForce RTX 5060 Ti处理办法】

报错信息 X:\Stable-Diffusion-WebUI\system\python\lib\site-packages\torch\cuda\__init__.py:215: UserWarning: NVIDIA GeForce RTX 5060 Ti with CUDA capability sm_120 is not compatible with the current PyTorch installation. The current PyTorch install supports…

Docker部署PaddleX实现PaddleOcr

Docker部署PaddleX实现PaddleOcr 一、版本说明二、安装PaddleX三、基础服务化部署四、接口调用实现表格识别五、调参优化一、版本说明 PaddleX 3.0Ubuntu20.04.1Docker version 26.1.3, build 26.1.3-0ubuntu1~20.04.1二、安装PaddleX 查看服务器信息 docker安装PaddleX 根据 …

深入学习c++之---AVL树

VL树简介​ AVL树是一种自平衡二叉搜索树&#xff0c;通过平衡因子&#xff08;Balance Factor, BF&#xff09;​和旋转操作&#xff0c;确保树始终保持平衡&#xff0c;避免退化成链表&#xff0c;从而保证查找、插入、删除的时间复杂度稳定在 ​O(log n)​。 ​核心特点​…