跳转至

Sign计算样例

本文档包含生成api数字签名的代码样例,供开发者参考。

样例使用说明

  1. 代码样例不能直接运行,trade_no1737961376859280、api_key25695e939c864ceebbd1df0ccccaee47等信息都是虚构的,请替换成您自己的信息。
  2. 在下面的代码示例中,不同编程语言,甚至同一语言每次执行得到的 url 可能都有所不同,表现为参数的顺序不同,但这并不影响正确性。只要所有参数都存在,并且签名串计算正确即可。
  3. 使用代码样例过程中遇到问题请联系售后客服,我们会为您提供技术支持。

Python3

Python3计算Sign示例

使用提示

  1. 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示例

使用提示

  1. 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示例

使用提示

  1. 使用前需要安装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;

没有您在使用的编程语言示例?

因开发语言太多,如果没有找到您的编程语言示例,请您联系客服处理!
Back to top