Sign计算样例¶
本文档包含生成api数字签名的代码样例,供开发者参考。
样例使用说明
- 代码样例不能直接运行,trade_no
1737961376859280
、api_key25695e939c864ceebbd1df0ccccaee47
等信息都是虚构的,请替换成您自己的信息。 - 在下面的代码示例中,不同编程语言,甚至同一语言每次执行得到的 url 可能都有所不同,表现为参数的顺序不同,但这并不影响正确性。只要所有参数都存在,并且签名串计算正确即可。
- 使用代码样例过程中遇到问题请联系售后客服,我们会为您提供技术支持。
Python3¶
Python3计算Sign示例
使用提示
- requests不是python原生库,需要安装才能使用:
pip install requests
import hashlib
import requests
class SignKit:
post_charset = "UTF-8"
file_charset = "UTF-8"
@staticmethod
def md5_sign(params, secret):
return SignKit.md5(SignKit.get_sign_content(params) + '&key=' + secret)
@staticmethod
def get_sign_content(params):
params.pop('sign', None)
sorted_params = sorted(params.items())
string_to_be_signed = ''
for k, v in sorted_params:
if not SignKit.check_empty(v) and not v.startswith('@'):
v = SignKit.character(v, SignKit.post_charset)
if not string_to_be_signed:
string_to_be_signed += f'{k}={v}'
else:
string_to_be_signed += f'&{k}={v}'
return string_to_be_signed
@staticmethod
def character(data, target_charset):
if not SignKit.check_empty(data):
file_type = SignKit.file_charset
if file_type.lower() != target_charset.lower():
return data.encode(target_charset).decode(target_charset)
return data
@staticmethod
def check_empty(value):
return value is None or value.strip() == ''
@staticmethod
def md5(input_str):
return hashlib.md5(input_str.encode()).hexdigest()
# 以下使用示例为提取【动态代理】,仅供参考
# 具体API参数说明请参照:https://www.juliangip.com/help/api/dynamic/
if __name__ == '__main__':
trade_no = '1737961376859280'
api_key = '25695e939c864ceebbd1df0ccccaee47'
method = 'GET' # 请求方式
ApiUrl = 'http://v2.api.juliangip.com/dynamic/getips'
# 除sign外的所有参数都放入params
# 具体
params = {
'trade_no': trade_no,
'num': '1',
'pt': '1',
}
# 计算签名
sign = SignKit.md5_sign(params, api_key)
params['sign'] = sign
# 发起请求
res = requests.get(ApiUrl, params=params)
print(res.text)
Java¶
Java计算Sign示例
使用提示
- hutool不是Java原生库,需要安装hutool才能使用
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.core.util.StrUtil;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.Map;
import java.net.URLEncoder;
import java.util.*;
public class newTest {
public static void main(String[] args) {
String trade_no = "1737961376859280";
String key = "25695e939c864ceebbd1df0ccccaee47";
Map<String, String> params_sign = new HashMap<>();
params_sign.put("trade_no", trade_no);
params_sign.put("num","1");
params_sign.put("pt","1");
String value = formatUrlMap(params_sign, false, false);
String _value = value + "&key=" + key;
String sign = DigestUtil.md5Hex(_value);
value = value + "&sign=" + sign;
String url = "http://v2.api.juliangip.com/dynamic/getips?" + value;
System.out.println(HttpUtil.get(url));;
}
/**
* 计算签名
*
* @param object 对象
* @param appKey 秘钥
* @return 请求参数
* @throws IllegalAccessException
*/
public static Map<String, Object> getParams(Object object, String appKey) throws IllegalAccessException {
Map<String, Object> params = getObjectToMap(object);
Map<String, Object> cleanParams = cleanParams(params);
String value = formatUrlMap(cleanParams, false, false);
value = value + "&key=" + appKey;
String sign = SecureUtil.md5(value);
cleanParams.put("sign", sign);
return cleanParams;
}
/**
* 对象转map
*
* @param obj
* @return
* @throws IllegalAccessException
*/
public static Map<String, Object> getObjectToMap(Object obj) throws IllegalAccessException {
Map<String, Object> map = new LinkedHashMap<String, Object>();
Class<?> clazz = obj.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
if (StrUtil.equals(fieldName, "key")) {
continue;
}
Object value = field.get(obj);
if (value == null) {
value = "";
}
map.put(fieldName, value);
}
return map;
}
/**
* 格式化参数,去掉为空的参数
*
* @param kv 所有参数
* @return
*/
public static Map<String, Object> cleanParams(Map<String, Object> kv) {
Map<String, Object> params = new HashMap<>();
for (Map.Entry<String, Object> entry : kv.entrySet()) {
String value = String.valueOf(entry.getValue());
if (StrUtil.isBlank(value)) {
//如果不存在值则直接清理掉
continue;
}
params.put(entry.getKey(), entry.getValue());
}
return params;
}
/**
* 方法用途: 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序),并且生成url参数串<br>
*
* @param paraMap 要排序的Map对象
* @param urlEncode 是否需要URLENCODE
* @param keyToLower 是否需要将Key转换为全小写 true:key转化成小写,false:不转化
* @return
*/
public static String formatUrlMap(Map<String, Object> paraMap, boolean urlEncode, boolean keyToLower) {
String buff = "";
Map<String, Object> tmpMap = paraMap;
try {
List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(tmpMap.entrySet());
Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
@Override
public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
return (o1.getKey()).toString().compareTo(o2.getKey());
}
});
StringBuilder buf = new StringBuilder();
for (Map.Entry<String, Object> item : infoIds) {
String key = item.getKey();
String val = String.valueOf(item.getValue());
if (urlEncode) {
val = URLEncoder.encode(val, "utf-8");
}
if (keyToLower) {
buf.append(key.toLowerCase() + "=" + val);
} else {
buf.append(key + "=" + val);
}
buf.append("&");
}
buff = buf.toString();
if (buff.isEmpty() == false) {
buff = buff.substring(0, buff.length() - 1);
}
} catch (Exception e) {
return null;
}
return buff;
}
}
GoLang¶
Golang计算Sign示例
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"sort"
"strings"
)
// SignKit provides methods for signing data using MD5
type SignKit struct {
postCharset string
fileCharset string
}
// NewSignKit creates a new instance of SignKit
func NewSignKit() *SignKit {
return &SignKit{
postCharset: "UTF-8",
fileCharset: "UTF-8",
}
}
// MD5Sign generates an MD5 signature for the given parameters and secret key
func (s *SignKit) MD5Sign(params map[string]string, secret string) string {
return s.md5(s.getSignContent(params) + "&key=" + secret)
}
func (s *SignKit) getSignContent(params map[string]string) string {
delete(params, "sign")
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var stringToBeSigned strings.Builder
for i, k := range keys {
v := params[k]
if !s.checkEmpty(v) && !strings.HasPrefix(v, "@") {
v = s.character(v, s.postCharset)
if i == 0 {
stringToBeSigned.WriteString(k + "=" + v)
} else {
stringToBeSigned.WriteString("&" + k + "=" + v)
}
}
}
return stringToBeSigned.String()
}
func (s *SignKit) character(data, targetCharset string) string {
if !s.checkEmpty(data) {
fileType := s.fileCharset
if strings.ToLower(fileType) != strings.ToLower(targetCharset) {
result, err := decodeString(data, targetCharset)
if err == nil {
return result
}
}
}
return data
}
func (s *SignKit) checkEmpty(value string) bool {
return value == "" || strings.TrimSpace(value) == ""
}
func (s *SignKit) md5(input string) string {
hash := md5.New()
hash.Write([]byte(input))
return hex.EncodeToString(hash.Sum(nil))
}
func decodeString(data, targetCharset string) (string, error) {
decoded, err := hex.DecodeString(data)
if err != nil {
return "", err
}
return string(decoded), nil
}
// 以下使用示例为提取【动态代理】,仅供参考
// 具体API参数说明请参照:https://www.juliangip.com/help/api/dynamic/
func main() {
tradeNo := "1737961376859280"
apiKey := "25695e939c864ceebbd1df0ccccaee47"
apiUrl := "http://v2.api.juliangip.com/dynamic/getips"
// 除sign外的所有参数都放入params
params := map[string]string{
"trade_no": tradeNo,
"num": "1",
"pt": "1",
}
// 计算签名
sign := NewSignKit().MD5Sign(params, apiKey)
params["sign"] = sign
// 将params参数map转为string
var paramsStr string
for k, v := range params {
paramsStr += fmt.Sprintf("%s=%s&", k, v)
}
// 发起 GET 请求
response, err := http.Get(fmt.Sprintf("%s?%s", apiUrl, paramsStr))
if err != nil {
fmt.Println("Error:", err)
return
}
defer response.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return
}
// 打印响应内容
fmt.Println("Response Body:", string(body))
}
Node.js¶
Node.js计算Sign示例
使用提示
- 使用前需要安装
axios
才能使用:npm i axios
const axios = require('axios');
const crypto = require('crypto');
class SignKit {
static postCharset = "UTF-8";
static fileCharset = "UTF-8";
static md5Sign(params, secret) {
return SignKit.md5(SignKit.getSignContent(params) + '&key=' + secret);
}
static getSignContent(params) {
delete params['sign'];
const keys = Object.keys(params).sort();
let stringToBeSigned = '';
for (const key of keys) {
const value = params[key];
if (!SignKit.checkEmpty(value) && !value.startsWith('@')) {
const encodedValue = SignKit.character(value, SignKit.postCharset);
if (!stringToBeSigned) {
stringToBeSigned += `${key}=${encodedValue}`;
} else {
stringToBeSigned += `&${key}=${encodedValue}`;
}
}
}
return stringToBeSigned;
}
static character(data, targetCharset) {
if (!SignKit.checkEmpty(data)) {
const fileType = SignKit.fileCharset.toLowerCase();
if (fileType !== targetCharset.toLowerCase()) {
return Buffer.from(data, fileType).toString(targetCharset);
}
}
return data;
}
static checkEmpty(value) {
return value === null || value.trim() === '';
}
static md5(input) {
return crypto.createHash('md5').update(input).digest('hex');
}
}
// 以下使用示例为提取【动态代理】,仅供参考
// 具体API参数说明请参照:https://www.juliangip.com/help/api/dynamic/
// 除 sign 外的所有参数都放入 params
const params = {
trade_no: '1737961376859280',
num: '1',
pt: '1',
};
// 计算签名
const sign = SignKit.md5Sign(params, '25695e939c864ceebbd1df0ccccaee47');
params.sign = sign;
// 发起请求
const apiUrl = 'http://v2.api.juliangip.com/dynamic/getips';
axios.get(apiUrl, { params })
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
php¶
PHP计算Sign示例
<?php
class SignKit
{
protected static string $postCharset = "UTF-8";
protected static string $fileCharset = "UTF-8";
/**
* MD5 加密
* @param array $params
* @param string $secret
* @return string
*/
public static function md5Sign(array $params, string $secret): string
{
return md5(self::getSignContent($params) . '&key=' . $secret);
}
/**
* 获取加签字符串
* @param $params
* @return string
*/
protected static function getSignContent($params): string
{
unset($params['sign']); // 删除Sign
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === self::checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = self::character($v, self::$postCharset);
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset($k, $v);
return $stringToBeSigned;
}
/**
* 转换字符集编码
* @param $data
* @param $targetCharset
* @return string
*/
protected static function character($data, $targetCharset): string
{
if (!empty($data)) {
$fileType = self::$fileCharset;
if (strcasecmp($fileType, $targetCharset) != 0) {
$data = mb_convert_encoding($data, $targetCharset);
}
}
return $data;
}
/**
* 校验$value是否非空
* if not set ,return true;
* if is null , return true;
**/
protected static function checkEmpty($value): bool
{
if (!isset($value))
return true;
if (trim($value) === "")
return true;
return false;
}
}
// 以下使用示例为提取【动态代理】,仅供参考
// 具体API参数说明请参照:https://www.juliangip.com/help/api/dynamic/
// 声明请求地址
$apiUrl = "http://v2.api.juliangip.com/dynamic/getips";
// 请求参数
$params = [
"trade_no" => "1737961376859280",
"num" => 1,
"pt" => 1,
];
$apiKey = "25695e939c864ceebbd1df0ccccaee47";
// 计算sign
$params["sign"] = SignKit::md5Sign($params, $apiKey);
// 组装请求地址
$apiUrl .= "?" . http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$result = curl_exec($ch);
curl_close($ch);
echo $result;
没有您在使用的编程语言示例?
因开发语言太多,如果没有找到您的编程语言示例,请您联系客服处理!