import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson2.JSON;
import com.iizan.common.base.KvTree;
import com.iizan.common.enums.CommonEnum;
import com.iizan.common.enums.Constants;
import com.iizan.common.enums.EncryptType;
import com.iizan.common.openapp.OpenAppConfig;
import com.iizan.common.util.data.IDUtil;
import com.iizan.common.util.encrypt.AesUtils;
import com.iizan.common.util.encrypt.Des3Utils;
import com.iizan.common.util.encrypt.MD5;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
public class OpenAppUtil {
@Data
public static class OpenAppDTO {
private OpenAppConfig config;
private String requestId;
private String path;
private KvTree data;
public OpenAppDTO(String path, KvTree data) {
this.path = path;
this.data = data;
}
public OpenAppDTO config(OpenAppConfig config) {
this.config = config;
return this;
}
public OpenAppDTO requestId(String requestId) {
this.requestId = requestId;
return this;
}
public OpenAppDTO set(String key,Object value) {
data.set(key,value);
return this;
}
public OpenAppDTO set(KvTree datas) {
data.putAll(datas);
return this;
}
public static OpenAppDTO by(String path, KvTree data) {
return new OpenAppDTO(path, data);
}
public static OpenAppDTO by(String path) {
return new OpenAppDTO(path, KvTree.by());
}
public static OpenAppDTO by(String path,OpenAppConfig config) {
return new OpenAppDTO(path, KvTree.by()).config(config);
}
}
public static String send(OpenAppDTO dto){
String requestId = dto.getRequestId();
String path = dto.getPath();
KvTree data = dto.getData();
OpenAppConfig config = dto.getConfig();
String appId = config.getAppId();
String baseUrl = config.getBaseUrl();
String password = config.getPassword();
String secret = config.getSecret();
String platformCode = config.getPlatformCode();
String encryptType = config.getEncryptType();
String timestamp=System.currentTimeMillis()+"";
if(requestId==null){
requestId= IDUtil.uuid();
}
//1.构建签名参数
Map sourceData = KvTree.by(data)
.set("appId",appId)
.set("timestamp",timestamp)
.set("requestId",requestId)
;
String signSource = sourceData.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey()) // 按键排序
.filter(entry -> entry.getValue() != null)
.map(entry -> entry.getKey() + "=" + (entry.getValue()==null?"":entry.getValue())) // 格式化为 k=v
.collect(Collectors.joining("&"));
//2.MD5签名
String sign = MD5.sign(signSource + password, Constants.CHARSET_UTF8);
//3.构建请求头
Map> headers=new HashMap<>();
headers.put("content-type",List.of(CommonEnum.MediaTypes.JSON_UTF_8.getType()));//添加请求头
headers.put("timestamp",List.of(timestamp));//按当前时间生成,系统会校验该值
headers.put("appId",List.of(appId));//系统分配
headers.put("platformCode",List.of(platformCode));//系统分配
headers.put("requestId",List.of(requestId));//每次请求生成唯一请求ID,长度不超过32位
headers.put("sign",List.of(sign));
//4.请求数据,如果需要加密则加密数据
String requestData = null;
if(EncryptType.DES.name().equals(encryptType)){
requestData = Des3Utils.encode(JSON.toJSONString(data),secret);
}else if(EncryptType.AES.name().equals(encryptType)){
requestData = AesUtils.encode(JSON.toJSONString(data),secret);
}else if(EncryptType.RSA.name().equals(encryptType)){
//requestData = RSAUtils.encryptByPublicKey(JSON.toJSONString(data),secret);
}else {
requestData = JSON.toJSONString(data);
}
long startTime=System.currentTimeMillis();
//发送POST请求(仅支持 post)
log.info("OPENAPI请求开始:{}-{} -> {} {}",path,requestId,data,requestData);
try{
String body = HttpRequest.post(baseUrl+path)
.body(requestData)
.header(headers)
.execute()
.body();
log.info("OPENAPI请求结果:{}-{} -> {} ({}ms)",path,requestId,body,(System.currentTimeMillis()-startTime));
return body;
}catch (Exception e){
e.printStackTrace();
log.error("OPENAPI请求异常:{}-{} -> {} ({}ms)",baseUrl+path,requestId,e.getMessage(),(System.currentTimeMillis()-startTime));
return null;
}
}
public static void main(String[] args) {
OpenAppConfig config = new OpenAppConfig();
config.setBaseUrl("https://api.zuzuda.com/openapp");//https://api.zuzuda.com/openapp + /logistics/100001 接口路径
config.setPlatformCode("100000");//系统分配
config.setAppId("6d1b0dbf65534258aff6791eccf94ec4");//系统分配
config.setSecret("9+XaxnFxe2GtQlOpS+==");//数据加密密钥,系统分配
config.setPassword("123456");//签名密码,系统分配
config.setEncryptType(EncryptType.DES.name());//数据加密方式,系统分配
OpenAppUtil.OpenAppDTO dto = OpenAppUtil.OpenAppDTO.by("/logistics/100001", KvTree.by("expressNo","773374947375732").set("code","STO")).config(config);
String result = OpenAppUtil.send(dto);
}
}
package main
import (
"crypto/md5"
"crypto/des"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strings"
"time"
)
type OpenAppConfig struct {
AppId string `json:"appId"`
BaseUrl string `json:"baseUrl"`
Password string `json:"password"`
Secret string `json:"secret"`
PlatformCode string `json:"platformCode"`
EncryptType string `json:"encryptType"`
}
type OpenAppDTO struct {
Config *OpenAppConfig
RequestId string
Path string
Data map[string]interface{}
}
func (dto *OpenAppDTO) Set(key string, value interface{}) *OpenAppDTO {
dto.Data[key] = value
return dto
}
func NewOpenAppDTO(path string, data map[string]interface{}) *OpenAppDTO {
if data == nil {
data = make(map[string]interface{})
}
return &OpenAppDTO{
Path: path,
Data: data,
}
}
func Send(dto *OpenAppDTO) string {
config := dto.Config
requestId := dto.RequestId
path := dto.Path
data := dto.Data
if requestId == "" {
requestId = generateUUID()
}
timestamp := fmt.Sprintf("%d", time.Now().UnixNano()/1e6)
// 1. 构建签名参数
sourceData := make(map[string]interface{})
for k, v := range data {
sourceData[k] = v
}
sourceData["appId"] = config.AppId
sourceData["timestamp"] = timestamp
sourceData["requestId"] = requestId
// 排序并构建签名字符串
var keys []string
for k, v := range sourceData {
if v != nil {
keys = append(keys, k)
}
}
sort.Strings(keys)
var signSource strings.Builder
for i, k := range keys {
v := sourceData[k]
strValue := ""
if v != nil {
strValue = fmt.Sprintf("%v", v)
}
signSource.WriteString(k + "=" + strValue)
if i < len(keys)-1 {
signSource.WriteString("&")
}
}
// 2. MD5签名
hash := md5.Sum([]byte(signSource.String() + config.Password))
sign := hex.EncodeToString(hash[:])
// 3. 请求数据加密
var requestData string
jsonData, _ := json.Marshal(data)
switch config.EncryptType {
case "DES":
requestData = des3Encode(string(jsonData), config.Secret)
case "AES":
requestData = aesEncode(string(jsonData), config.Secret)
default:
requestData = string(jsonData)
}
// 4. 发送请求
client := &http.Client{}
req, err := http.NewRequest("POST", config.BaseUrl+path, strings.NewReader(requestData))
if err != nil {
return ""
}
req.Header.Set("content-type", "application/json; charset=utf-8")
req.Header.Set("timestamp", timestamp)
req.Header.Set("appId", config.AppId)
req.Header.Set("platformCode", config.PlatformCode)
req.Header.Set("requestId", requestId)
req.Header.Set("sign", sign)
resp, err := client.Do(req)
if err != nil {
return ""
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
return string(body)
}
func des3Encode(data, key string) string {
block, err := des.NewTripleDESCipher([]byte(key))
if err != nil {
return ""
}
dataBytes := []byte(data)
blockSize := block.BlockSize()
dataBytes = pkcs5Padding(dataBytes, blockSize)
ciphertext := make([]byte, len(dataBytes))
mode := cipher.NewCBCEncrypter(block, []byte(key)[:blockSize])
mode.CryptBlocks(ciphertext, dataBytes)
return base64.StdEncoding.EncodeToString(ciphertext)
}
func aesEncode(data, key string) string {
// AES加密实现
return base64.StdEncoding.EncodeToString([]byte(data))
}
func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func generateUUID() string {
return fmt.Sprintf("%x", time.Now().UnixNano())
}
func main() {
config := &OpenAppConfig{
BaseUrl: "https://api.zuzuda.com/openapp",
PlatformCode: "100000",
AppId: "6d1b0dbf65534258aff6791eccf94ec4",
Secret: "9+XaxnFxe2GtQlOpS+==",
Password: "123456",
EncryptType: "DES",
}
data := map[string]interface{}{
"expressNo": "773374947375732",
"code": "STO",
}
dto := NewOpenAppDTO("/logistics/100001", data)
dto.Config = config
result := Send(dto)
fmt.Println(result)
}
import hashlib
import hmac
import json
import time
import uuid
from typing import Dict, Any, Optional
import requests
from base64 import b64encode, b64decode
from Crypto.Cipher import DES3, AES
from Crypto.Util.Padding import pad
import urllib.parse
class OpenAppConfig:
def __init__(self, **kwargs):
self.app_id = kwargs.get('app_id')
self.base_url = kwargs.get('base_url')
self.password = kwargs.get('password')
self.secret = kwargs.get('secret')
self.platform_code = kwargs.get('platform_code')
self.encrypt_type = kwargs.get('encrypt_type')
class OpenAppDTO:
def __init__(self, path: str, data: Optional[Dict[str, Any]] = None):
self.config: Optional[OpenAppConfig] = None
self.request_id: Optional[str] = None
self.path = path
self.data = data or {}
def set(self, key: str, value: Any) -> 'OpenAppDTO':
self.data[key] = value
return self
def with_config(self, config: OpenAppConfig) -> 'OpenAppDTO':
self.config = config
return self
def with_request_id(self, request_id: str) -> 'OpenAppDTO':
self.request_id = request_id
return self
@classmethod
def by(cls, path: str, data: Optional[Dict[str, Any]] = None) -> 'OpenAppDTO':
return cls(path, data)
class OpenAppUtil:
@staticmethod
def send(dto: OpenAppDTO) -> Optional[str]:
config = dto.config
request_id = dto.request_id or str(uuid.uuid4()).replace('-', '')
path = dto.path
data = dto.data
timestamp = str(int(time.time() * 1000))
# 1. 构建签名参数
source_data = data.copy()
source_data['appId'] = config.app_id
source_data['timestamp'] = timestamp
source_data['requestId'] = request_id
# 过滤None值并排序
filtered_items = {k: v for k, v in source_data.items() if v is not None}
sorted_items = sorted(filtered_items.items())
# 构建签名字符串
sign_parts = []
for key, value in sorted_items:
sign_parts.append(f"{key}={value}")
sign_source = '&'.join(sign_parts)
# 2. MD5签名
sign_string = sign_source + config.password
sign = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
# 3. 请求数据加密
json_data = json.dumps(data, ensure_ascii=False)
if config.encrypt_type == 'DES':
request_data = OpenAppUtil.des3_encode(json_data, config.secret)
elif config.encrypt_type == 'AES':
request_data = OpenAppUtil.aes_encode(json_data, config.secret)
else:
request_data = json_data
# 4. 发送请求
headers = {
'content-type': 'application/json; charset=utf-8',
'timestamp': timestamp,
'appId': config.app_id,
'platformCode': config.platform_code,
'requestId': request_id,
'sign': sign
}
try:
start_time = time.time()
print(f"OPENAPI请求开始:{path}-{request_id} -> {data} {request_data}")
response = requests.post(
config.base_url + path,
data=request_data.encode('utf-8') if isinstance(request_data, str) else request_data,
headers=headers,
timeout=30
)
duration = int((time.time() - start_time) * 1000)
print(f"OPENAPI请求结果:{path}-{request_id} -> {response.text} ({duration}ms)")
return response.text
except Exception as e:
duration = int((time.time() - start_time) * 1000)
print(f"OPENAPI请求异常:{config.base_url}{path}-{request_id} -> {str(e)} ({duration}ms)")
return None
@staticmethod
def des3_encode(data: str, key: str) -> str:
"""3DES加密"""
# 确保key长度为24字节
key_bytes = key.encode('utf-8')
if len(key_bytes) != 24:
key_bytes = key_bytes.ljust(24, b'\0')[:24]
# 使用CBC模式
cipher = DES3.new(key_bytes, DES3.MODE_CBC, iv=b'\0' * 8)
padded_data = pad(data.encode('utf-8'), DES3.block_size)
encrypted = cipher.encrypt(padded_data)
return b64encode(encrypted).decode('utf-8')
@staticmethod
def aes_encode(data: str, key: str) -> str:
"""AES加密"""
# 确保key长度为16、24或32字节
key_bytes = key.encode('utf-8')
if len(key_bytes) not in [16, 24, 32]:
key_bytes = key_bytes.ljust(32, b'\0')[:32]
# 使用CBC模式
cipher = AES.new(key_bytes, AES.MODE_CBC, iv=b'\0' * 16)
padded_data = pad(data.encode('utf-8'), AES.block_size)
encrypted = cipher.encrypt(padded_data)
return b64encode(encrypted).decode('utf-8')
def main():
config = OpenAppConfig(
base_url="https://api.zuzuda.com/openapp",
platform_code="100000",
app_id="6d1b0dbf65534258aff6791eccf94ec4",
secret="9+XaxnFxe2GtQlOpS+==",
password="123456",
encrypt_type="DES"
)
data = {
"expressNo": "773374947375732",
"code": "STO"
}
dto = OpenAppDTO.by("/logistics/100001", data).with_config(config)
result = OpenAppUtil.send(dto)
print(result)
if __name__ == "__main__":
main()
const crypto = require('crypto');
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');
class OpenAppConfig {
constructor(config) {
this.appId = config.appId;
this.baseUrl = config.baseUrl;
this.password = config.password;
this.secret = config.secret;
this.platformCode = config.platformCode;
this.encryptType = config.encryptType;
}
}
class OpenAppDTO {
constructor(path, data = {}) {
this.config = null;
this.requestId = null;
this.path = path;
this.data = data;
}
set(key, value) {
this.data[key] = value;
return this;
}
withConfig(config) {
this.config = config;
return this;
}
withRequestId(requestId) {
this.requestId = requestId;
return this;
}
static by(path, data = {}) {
return new OpenAppDTO(path, data);
}
}
class OpenAppUtil {
static async send(dto) {
const config = dto.config;
let requestId = dto.requestId || uuidv4().replace(/-/g, '');
const path = dto.path;
const data = dto.data;
const timestamp = Date.now().toString();
// 1. 构建签名参数
const sourceData = { ...data };
sourceData.appId = config.appId;
sourceData.timestamp = timestamp;
sourceData.requestId = requestId;
// 排序并构建签名字符串
const sortedKeys = Object.keys(sourceData)
.filter(key => sourceData[key] != null)
.sort();
const signParts = [];
for (const key of sortedKeys) {
const value = sourceData[key] === null ? '' : sourceData[key];
signParts.push(`${key}=${value}`);
}
const signSource = signParts.join('&');
// 2. MD5签名
const sign = crypto
.createHash('md5')
.update(signSource + config.password)
.digest('hex');
// 3. 请求数据加密
let requestData;
const jsonData = JSON.stringify(data);
switch (config.encryptType) {
case 'DES':
requestData = this.des3Encode(jsonData, config.secret);
break;
case 'AES':
requestData = this.aesEncode(jsonData, config.secret);
break;
default:
requestData = jsonData;
}
// 4. 构建请求头
const headers = {
'content-type': 'application/json; charset=utf-8',
'timestamp': timestamp,
'appId': config.appId,
'platformCode': config.platformCode,
'requestId': requestId,
'sign': sign
};
const startTime = Date.now();
console.log(`OPENAPI请求开始:${path}-${requestId} -> ${jsonData} ${requestData}`);
try {
const response = await axios.post(config.baseUrl + path, requestData, {
headers: headers,
timeout: 30000
});
const duration = Date.now() - startTime;
console.log(`OPENAPI请求结果:${path}-${requestId} -> ${JSON.stringify(response.data)} (${duration}ms)`);
return response.data;
} catch (error) {
const duration = Date.now() - startTime;
console.error(`OPENAPI请求异常:${config.baseUrl}${path}-${requestId} -> ${error.message} (${duration}ms)`);
return null;
}
}
static des3Encode(data, key) {
// 3DES加密
const keyBuffer = Buffer.from(key, 'utf8');
const iv = Buffer.alloc(8, 0); // 使用零向量
// 补全key到24字节
const fullKey = Buffer.alloc(24);
keyBuffer.copy(fullKey);
const cipher = crypto.createCipheriv('des-ede3-cbc', fullKey, iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
static aesEncode(data, key) {
// AES加密
const keyBuffer = Buffer.from(key, 'utf8');
const iv = Buffer.alloc(16, 0); // 使用零向量
// 根据key长度确定算法
let algorithm;
if (keyBuffer.length === 16) {
algorithm = 'aes-128-cbc';
} else if (keyBuffer.length === 24) {
algorithm = 'aes-192-cbc';
} else {
algorithm = 'aes-256-cbc';
}
const cipher = crypto.createCipheriv(algorithm, keyBuffer, iv);
let encrypted = cipher.update(data, 'utf8', 'base64');
encrypted += cipher.final('base64');
return encrypted;
}
}
// 使用示例
async function main() {
const config = new OpenAppConfig({
baseUrl: 'https://api.zuzuda.com/openapp',
platformCode: '100000',
appId: '6d1b0dbf65534258aff6791eccf94ec4',
secret: '9+XaxnFxe2GtQlOpS+=',
password: '123456',
encryptType: 'DES'
});
const data = {
expressNo: '773374947375732',
code: 'STO'
};
const dto = OpenAppDTO.by('/logistics/100001', data).withConfig(config);
const result = await OpenAppUtil.send(dto);
console.log(result);
}
// 执行
main().catch(console.error);
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct {
char* appId;
char* baseUrl;
char* password;
char* secret;
char* platformCode;
char* encryptType;
} OpenAppConfig;
typedef struct {
OpenAppConfig* config;
char* requestId;
char* path;
json_t* data;
} OpenAppDTO;
// 简化版实现,只展示核心逻辑
char* openapp_send(OpenAppDTO* dto) {
// 生成时间戳
char timestamp[20];
snprintf(timestamp, sizeof(timestamp), "%lld", (long long)time(NULL) * 1000);
// 生成签名(简化版)
char sign[33];
// ... 签名逻辑 ...
// 加密数据
char* requestData = NULL;
char* jsonData = json_dumps(dto->data, JSON_COMPACT);
if (strcmp(dto->config->encryptType, "DES") == 0) {
// DES加密
} else if (strcmp(dto->config->encryptType, "AES") == 0) {
// AES加密
} else {
requestData = strdup(jsonData);
}
// 发送HTTP请求
CURL* curl = curl_easy_init();
if (curl) {
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "content-type: application/json; charset=utf-8");
// ... 添加其他header ...
curl_easy_setopt(curl, CURLOPT_URL, dto->config->baseUrl);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestData);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
// 执行请求
// ...
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
}
free(jsonData);
if (requestData) free(requestData);
return NULL;
}
#include
#include
#include
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using Newtonsoft.Json;
using System.Linq;
namespace OpenAppUtil
{
public class OpenAppConfig
{
public string AppId { get; set; }
public string BaseUrl { get; set; }
public string Password { get; set; }
public string Secret { get; set; }
public string PlatformCode { get; set; }
public string EncryptType { get; set; }
}
public class OpenAppDTO
{
public OpenAppConfig Config { get; set; }
public string RequestId { get; set; }
public string Path { get; set; }
public Dictionary Data { get; set; }
public OpenAppDTO(string path, Dictionary data = null)
{
Path = path;
Data = data ?? new Dictionary();
}
public OpenAppDTO Set(string key, object value)
{
Data[key] = value;
return this;
}
public OpenAppDTO Config(OpenAppConfig config)
{
Config = config;
return this;
}
public static OpenAppDTO By(string path, Dictionary data = null)
{
return new OpenAppDTO(path, data);
}
}
public class OpenAppUtil
{
public static async Task Send(OpenAppDTO dto)
{
var config = dto.Config;
var requestId = dto.RequestId;
var path = dto.Path;
var data = dto.Data;
if (string.IsNullOrEmpty(requestId))
{
requestId = Guid.NewGuid().ToString("N");
}
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();
// 1. 构建签名参数
var sourceData = new Dictionary(data)
{
["appId"] = config.AppId,
["timestamp"] = timestamp,
["requestId"] = requestId
};
// 排序并构建签名字符串
var sortedParams = sourceData
.Where(kv => kv.Value != null)
.OrderBy(kv => kv.Key)
.Select(kv => $"{kv.Key}={kv.Value}");
var signSource = string.Join("&", sortedParams);
// 2. MD5签名
using var md5 = MD5.Create();
var signBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(signSource + config.Password));
var sign = BitConverter.ToString(signBytes).Replace("-", "").ToLower();
// 3. 请求数据加密
string requestData;
var jsonData = JsonConvert.SerializeObject(data);
switch (config.EncryptType)
{
case "DES":
requestData = Des3Encode(jsonData, config.Secret);
break;
case "AES":
requestData = AesEncode(jsonData, config.Secret);
break;
default:
requestData = jsonData;
break;
}
// 4. 发送请求
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("timestamp", timestamp);
client.DefaultRequestHeaders.Add("appId", config.AppId);
client.DefaultRequestHeaders.Add("platformCode", config.PlatformCode);
client.DefaultRequestHeaders.Add("requestId", requestId);
client.DefaultRequestHeaders.Add("sign", sign);
var content = new StringContent(requestData, Encoding.UTF8, "application/json");
var response = await client.PostAsync(config.BaseUrl + path, content);
return await response.Content.ReadAsStringAsync();
}
private static string Des3Encode(string data, string key)
{
using var des = TripleDES.Create();
des.Key = Encoding.UTF8.GetBytes(key.PadRight(24).Substring(0, 24));
des.Mode = CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
using var encryptor = des.CreateEncryptor();
var bytes = Encoding.UTF8.GetBytes(data);
var result = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return Convert.ToBase64String(result);
}
private static string AesEncode(string data, string key)
{
using var aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32));
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.IV = new byte[16];
using var encryptor = aes.CreateEncryptor();
var bytes = Encoding.UTF8.GetBytes(data);
var result = encryptor.TransformFinalBlock(bytes, 0, bytes.Length);
return Convert.ToBase64String(result);
}
}
class Program
{
static async Task Main(string[] args)
{
var config = new OpenAppConfig
{
BaseUrl = "https://api.zuzuda.com/openapp",
PlatformCode = "100000",
AppId = "6d1b0dbf65534258aff6791eccf94ec4",
Secret = "9+XaxnFxe2GtQlOpS+==",
Password = "123456",
EncryptType = "DES"
};
var data = new Dictionary
{
["expressNo"] = "773374947375732",
["code"] = "STO"
};
var dto = OpenAppDTO.By("/logistics/100001", data);
dto.Config(config);
var result = await OpenAppUtil.Send(dto);
Console.WriteLine(result);
}
}
}
<?php
class OpenAppUtil
{
public static function send(OpenAppDTO $dto)
{
$requestId = $dto->getRequestId();
$path = $dto->getPath();
$data = $dto->getData();
$config = $dto->getConfig();
$appId = $config->getAppId();
$baseUrl = $config->getBaseUrl();
$password = $config->getPassword();
$secret = $config->getSecret();
$platformCode = $config->getPlatformCode();
$encryptType = $config->getEncryptType();
$timestamp = (string)(round(microtime(true) * 1000));
if ($requestId === null) {
$requestId = self::uuid();
}
// 1. 构建签名参数
$sourceData = array_merge($data, [
'appId' => $appId,
'timestamp' => $timestamp,
'requestId' => $requestId
]);
// 过滤空值并按键排序
$sourceData = array_filter($sourceData, function($value) {
return $value !== null;
});
ksort($sourceData);
// 构建签名字符串
$signSource = '';
foreach ($sourceData as $key => $value) {
$signSource .= $key . '=' . ($value === null ? '' : $value) . '&';
}
$signSource = rtrim($signSource, '&');
// 2. MD5签名
$sign = md5($signSource . $password);
// 3. 构建请求头
$headers = [
'content-type: application/json; charset=utf-8',
'timestamp: ' . $timestamp,
'appId: ' . $appId,
'platformCode: ' . $platformCode,
'requestId: ' . $requestId,
'sign: ' . $sign,
];
// 4. 请求数据,如果需要加密则加密数据
$requestData = json_encode($data);
if ($encryptType === 'DES') {
$requestData = self::des3Encode($requestData, $secret);
} elseif ($encryptType === 'AES') {
$requestData = self::aesEncode($requestData, $secret);
} elseif ($encryptType === 'RSA') {
// RSA加密,需要openssl扩展
// $requestData = self::rsaEncrypt($requestData, $secret);
}
$startTime = microtime(true) * 1000;
error_log("OPENAPI请求开始:{$path}-{$requestId} -> " . json_encode($data) . " " . $requestData);
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $baseUrl . $path);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$body = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
throw new Exception($error);
}
$endTime = microtime(true) * 1000;
$duration = round($endTime - $startTime);
error_log("OPENAPI请求结果:{$path}-{$requestId} -> {$body} ({$duration}ms)");
return $body;
} catch (Exception $e) {
$endTime = microtime(true) * 1000;
$duration = round($endTime - $startTime);
error_log("OPENAPI请求异常:{$baseUrl}{$path}-{$requestId} -> {$e->getMessage()} ({$duration}ms)");
return null;
}
}
private static function uuid()
{
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
private static function des3Encode($data, $key)
{
// 3DES加密实现,需要根据具体算法调整
$method = 'des-ede3';
$iv = substr($key, 0, 8); // 根据实际需求调整IV
return base64_encode(openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv));
}
private static function aesEncode($data, $key)
{
// AES加密实现
$method = 'aes-128-cbc';
$iv = substr($key, 0, 16); // 根据实际需求调整IV
return base64_encode(openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv));
}
public static function main()
{
$config = new OpenAppConfig();
$config->setBaseUrl('https://api.zuzuda.com/openapp');
$config->setPlatformCode('100000');
$config->setAppId('6d1b0dbf65534258aff6791eccf94ec4');
$config->setSecret('9+XaxnFxe2GtQlOpS+==');
$config->setPassword('123456');
$config->setEncryptType('DES');
$data = [
'expressNo' => '773374947375732',
'code' => 'STO'
];
$dto = OpenAppDTO::by('/logistics/100001', $data);
$dto->config($config);
$result = self::send($dto);
return $result;
}
}
class OpenAppDTO
{
private $config;
private $requestId;
private $path;
private $data;
public function __construct($path, $data = [])
{
$this->path = $path;
$this->data = $data;
}
public function getConfig()
{
return $this->config;
}
public function getRequestId()
{
return $this->requestId;
}
public function getPath()
{
return $this->path;
}
public function getData()
{
return $this->data;
}
public function config(OpenAppConfig $config)
{
$this->config = $config;
return $this;
}
public function requestId($requestId)
{
$this->requestId = $requestId;
return $this;
}
public function set($key, $value)
{
$this->data[$key] = $value;
return $this;
}
public function setData($datas)
{
$this->data = array_merge($this->data, $datas);
return $this;
}
public static function by($path, $data = [])
{
return new self($path, $data);
}
}
class OpenAppConfig
{
private $appId;
private $baseUrl;
private $password;
private $secret;
private $platformCode;
private $encryptType;
public function getAppId()
{
return $this->appId;
}
public function setAppId($appId)
{
$this->appId = $appId;
return $this;
}
public function getBaseUrl()
{
return $this->baseUrl;
}
public function setBaseUrl($baseUrl)
{
$this->baseUrl = $baseUrl;
return $this;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
return $this;
}
public function getSecret()
{
return $this->secret;
}
public function setSecret($secret)
{
$this->secret = $secret;
return $this;
}
public function getPlatformCode()
{
return $this->platformCode;
}
public function setPlatformCode($platformCode)
{
$this->platformCode = $platformCode;
return $this;
}
public function getEncryptType()
{
return $this->encryptType;
}
public function setEncryptType($encryptType)
{
$this->encryptType = $encryptType;
return $this;
}
}
// 使用示例
// $result = OpenAppUtil::main();