当前位置: 首页 > news >正文

手写海康OpenApi签名规范,实现手动调用api(sdk:artemis-http-client)

1. 前言:

artemis-http-clientsdk 中提供获取门禁事件图片的方法,但实际图片访问地址为该响应的重定向地址
问题来了:虽然他提供了 sdk ,但没有办法通过 sdk 获取重定向的地址于是产生了本文,自己通过hutools的 httpUtil调用

2. 签名工具类

HikSignUtil 记得先引入一下 artemis-http-client

packagecom.lxsy.util;importcn.hutool.core.codec.Base64;importcn.hutool.crypto.digest.DigestUtil;importcn.hutool.crypto.digest.HMac;importcn.hutool.crypto.digest.HmacAlgorithm;importjava.nio.charset.StandardCharsets;importjava.time.ZoneOffset;importjava.time.ZonedDateTime;importjava.time.format.DateTimeFormatter;importjava.util.HashMap;importjava.util.Map;/** * 海康 OpenAPI 签名工具类 * 签名算法:HmacSHA256 + Base64 */publicclassHikSignUtil{privatestaticfinalDateTimeFormatterRFC_1123_FORMATTER=DateTimeFormatter.RFC_1123_DATE_TIME.withZone(ZoneOffset.UTC);/** * 生成请求头(包含签名) * * @param appKey 应用Key * @param appSecret 应用Secret * @param url 请求的相对路径(如 /artemis/api/acs/v1/event/pictures) * @param body 请求体(JSON字符串) * @return 包含签名的请求头Map */publicstaticMap<String,String>buildHeaders(StringappKey,StringappSecret,Stringurl,Stringbody){// Content-MD5:请求体的MD5值,Base64编码StringcontentMd5=Base64.encode(DigestUtil.md5(body));// Date 头(RFC1123)Stringdate=RFC_1123_FORMATTER.format(ZonedDateTime.now(ZoneOffset.UTC));// 签名字符串拼接// httpHeaders = HTTP METHOD + "\n" + Accept + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n"// customHeaders = "x-ca-key" + ":" + appKey + "\n"// signString = httpHeaders + customHeaders + urlStringBuildersignBuilder=newStringBuilder();signBuilder.append("POST").append("\n");// HTTP METHODsignBuilder.append("*/*").append("\n");// AcceptsignBuilder.append(contentMd5).append("\n");// Content-MD5signBuilder.append("application/json").append("\n");// Content-TypesignBuilder.append(date).append("\n");// DatesignBuilder.append("x-ca-key:").append(appKey).append("\n");// customHeaderssignBuilder.append(url);// urlStringsignString=signBuilder.toString();// 使用 HmacSHA256 算法计算签名HMachmac=newHMac(HmacAlgorithm.HmacSHA256,appSecret.getBytes(StandardCharsets.UTF_8));Stringsignature=Base64.encode(hmac.digest(signString));// 构建请求头Map<String,String>headers=newHashMap<>();headers.put("Accept","*/*");headers.put("Content-Type","application/json");headers.put("Content-MD5",contentMd5);headers.put("Date",date);headers.put("x-ca-key",appKey);headers.put("x-ca-signature",signature);headers.put("x-ca-signature-headers","x-ca-key");returnheaders;}}

3. 使用

示例1

protectedstaticfinalArtemisConfigartemisConfig=newArtemisConfig("192.XX.13.XX:443","123","123");/** * 使用自建 HttpClient 调用海康接口,便于排查网络/签名问题 */publicstaticPageResponseResult<EventInfoDto>getEventListWithHttpClient(EventsRequesteventsRequest)throwsException{if(eventsRequest==null){eventsRequest=newEventsRequest();}Stringurl="/artemis/api/acs/v2/door/events";StringfullUrl="https://"+artemisConfig.getHost()+url;Stringbody=JSON.toJSONString(eventsRequest);Map<String,String>headers=HikSignUtil.buildHeaders(artemisConfig.getAppKey(),artemisConfig.getAppSecret(),url,body);try(CloseableHttpClienthttpClient=createHttpClient(false)){HttpPosthttpPost=newHttpPost(fullUrl);headers.forEach(httpPost::setHeader);httpPost.setEntity(newStringEntity(body,ContentType.APPLICATION_JSON));try(CloseableHttpResponseresponse=httpClient.execute(httpPost)){intstatus=response.getStatusLine().getStatusCode();StringrespBody=response.getEntity()==null?null:EntityUtils.toString(response.getEntity());if(status==HttpStatus.SC_OK){returncheckResp(respBody,newTypeReference<PageResponseResult<EventInfoDto>>(){});}thrownewException("获取事件列表失败,状态码: "+status+", 响应: "+respBody);}}}

示例2

protectedstaticfinalArtemisConfigartemisConfig=newArtemisConfig("192.XX.13.XX:443","123","123");publicstaticStringpictures(StringsvrIndexCode,StringpicUri)throwsException{Stringurl="/artemis/api/acs/v1/event/pictures";StringfullUrl="https://"+artemisConfig.getHost()+url;// 构建请求体PicturesRequestrequest=newPicturesRequest(svrIndexCode,picUri);Stringbody=JSON.toJSONString(request);// 使用签名工具生成请求头Map<String,String>headers=HikSignUtil.buildHeaders(artemisConfig.getAppKey(),artemisConfig.getAppSecret(),url,body);try(CloseableHttpClienthttpClient=createHttpClient(false)){HttpPosthttpPost=newHttpPost(fullUrl);headers.forEach(httpPost::setHeader);httpPost.setEntity(newStringEntity(body,ContentType.APPLICATION_JSON));try(CloseableHttpResponseresponse=httpClient.execute(httpPost)){intstatus=response.getStatusLine().getStatusCode();if(status==HttpStatus.SC_MOVED_TEMPORARILY||status==HttpStatus.SC_MOVED_PERMANENTLY||status==HttpStatus.SC_SEE_OTHER||status==HttpStatus.SC_TEMPORARY_REDIRECT||status==HTTP_STATUS_PERMANENT_REDIRECT){HeaderlocationHeader=response.getFirstHeader("Location");if(locationHeader!=null&&StrUtil.isNotBlank(locationHeader.getValue())){returnlocationHeader.getValue();}thrownewException("302重定向但未获取到Location头");}StringrespBody=response.getEntity()==null?null:EntityUtils.toString(response.getEntity());thrownewException("获取图片失败,状态码: "+status+", 响应: "+respBody);}}}
http://www.cnnetsun.cn/news/92395.html

相关文章:

  • LobeChat能否定制品牌LOGO?白标解决方案
  • navigatetominiprogram实战应用案例分享
  • 1小时验证创意:右键菜单管理工具原型开发
  • LobeChat能否对接土卫六湖泊数据?甲烷循环与外星地貌研究
  • Axolotl推理缓存:5倍性能提升与70%成本优化的架构革命
  • vue3事件处理详解
  • YOLO目标检测入门:手把手教你跑通第一个demo
  • 1小时搭建:VSCode远程开发环境原型
  • 电商项目实战:Vue3父子组件传值最佳实践
  • 【LLM基础教程】从序列切分到上下文窗口01_为什么序列建模必须切分数据
  • 备赛三--
  • 高并发时代的“确定性”挑战——为何稳定性正在成为 JVM 的下一场核心竞争?
  • C语言之最大公约数和最小公倍数问题
  • LobeChat能否对接Telegram Bot?跨平台消息同步实现
  • AI如何用博图加速工业自动化开发
  • C++:二叉搜索树(BST)完全指南(从概念原理、核心操作到底层实现)
  • Splashtop AEM 在 G2冬季报告中斩获“最佳预估 ROI”殊荣
  • 赋能传统硬件:具身智能如何激活工业机器人的二次生命
  • 【模板:求组合数】信息学奥赛一本通 1648:【例 1】「NOIP2011」计算系数 | 1866:【11NOIP提高组】计算系数 | 洛谷 P1313 [NOIP 2011 提高组] 计算系数
  • 金运环球:金价高位回落,非农与零售数据即将来袭
  • 活动力度大的门头招牌企业
  • 【毕业设计】基于JavaWeb的兽医站管理系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • Java毕设选题推荐:基于JavaWeb的兽医站管理系统的设计与实现现代化兽医站管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • Arduino配置8266开发板
  • 【课程设计/毕业设计】基于SpringBoot+Vue茶叶销售系统的设计与实现基于Java语言的茶叶销售系统的前端设计与实现【附源码、数据库、万字文档】
  • 41. 缺失的第一个正数
  • 打了一堆板子,才发现是VDD_EXT的锅
  • 技术亲民倒计时!飞猫 RedCap 轻量化 5G 随身 WiFi 即将上市!
  • # 深入 Ascend C 内存模型:掌握UB、GM与流水线优化,打造极致AI算子
  • 冥想第一千七百三十五天(1735)