添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
文档中心 · 公有云
  • 公有云
  • 医签宝

请求签名鉴权方式说明

更新时间:2024-07-02 18:12:23

1.请求签名鉴权简介

e签宝 API 网关对每次接口请求都进行调用鉴权验证,在调用API时,开发者需要使用应用密钥(AppSecret )按照e签宝 API 网关的约定方式对请求中的关键数据进行签名值计算,并将签名值添加到Header请求头的X-Tsign-Open-Ca-Signature参数中传输给e签宝 API 网关进行签名验证。e签宝 API 网关会对接收到的数据进行签名值计算,并与接收到请求签名值进行核对,若签名值不一致,视为无效签名,将拒绝本次API请求。

e签宝 优先推荐 开发者 使用请求签名鉴权方式 调用 API 接口。

关于请求签名鉴权的算法,e签宝目前提供两种加密方式, HmacSHA256 HmacSM3 算法。

  • 本篇文档是基于 HmacSHA256 算法的签名鉴权方式说明。
  • 如果需要 HmacSM3 算法, 请点击跳转 《基于HmacSM3算法的签名鉴权方式说明》

2.请求签名鉴权原理说明

(1)开发者计算请求签名的步骤如下:

  1. 按照e签宝 API 网关的约定方式,拼接生成一个用来进行签名计算的 待签名字符串
  2. 使用 AppSecret 对待签名字符串进行 HmacSHA256 加密处理,计算得出 请求签名值
  3. 将请求签名值及其他头部信息添加到Header请求头中,同时将请求参数与Header请求头一起构造成最终HTTP请求并进行发送。

(2)e签宝 API 网关验证签名的步骤如下:

  1. 从接收到的请求中提取关键数据,拼接生成一个用来进行签名计算的 待签名字符串
  2. 从接收到的请求头 X-Tsign-Open-App-Id 参数中读取开发者AppID,并查询其对应的 AppSecret;
  3. 使用 AppSecret 对待签名字符串进行 HmacSHA256 加密处理,计算得出 请求签名值
  4. 从接收到的请求头 X-Tsign-Open-Ca-Signature 参数中读取开发者计算的签名值,并对比e签宝 API 网关计算的签名值和开发者计算的签名值是否一致。

3.请求签名值计算过程说明

3.1 拼接待签名字符串

待签名字符串由以下7个字段组合拼接生成:

字段

字段说明

HTTPMethod

HTTP的请求方法,全部大写,例如:GET、POST。

Accept

请求头中 Accept 的值,建议统一为*/*。

Content-MD5

请求头中 Content-MD5 的值, 点击查看 Content-MD5 计算方法

GET 和 DELETE 请求且Body体无数据时,此参数可为 ""(空字符串)。

Content-Type

请求的与实体对应的MIME信息,例如:application/json; charset=UTF-8

请求头中的 Content-Type 值

GET 和 DELETE 请求且Body体无数据时,此参数可为 ""(空字符串)。

Date

请求头中的 Date 值,时间的描述格式需符合RFC822规范。

例如,Thu, 11 Jul 2015 15:33:24 GMT。

可为 ""(空字符串)。

Headers

用户可以选取指定的Header参与签名,将希望参与签名计算的Key与Value组合拼接成字符串,Key需按字典(ASCII码)升序排序。

可为 ""(空字符串)。

PathAndParameters

e签宝 API 的接口Url(注意不含https://{host}部分)

PathAndParameters 字段包含Path 和 Query 中的所有参数。例如:

/v3/files/123/keyword-positions?keywords=关键字1,关键字2

Query 参数对的Key需按字典(ASCII码)升序排序。

待签名字符串拼接后格式如下所示:

HTTPMethod
Accept
Content-MD5
Content-Type
Headers
PathAndParameters

字段之间使用\n间隔,若Headers为空,则不需要加\n,其他字段若为空都需要保留\n。注:大小写敏感。

public static void main(String[] args) {
    String HTTPMethod = "POST";
    String Accept = "*/*";
    String ContentMD5 = "uxydqKBMBy6x1siClKEQ6Q==";
    String ContentType = "application/json; charset=UTF-8";
    String Date = "";
    String Headers = "";
    String PathAndParameters = "/v3/sign-flow/create-by-file";
    // 组合拼接待签名字符串
    StringBuffer strBuff = new StringBuffer();
    strBuff.append(HTTPMethod).append("\n").append(Accept).append("\n").append(ContentMD5).append("\n")
        .append(ContentType).append("\n").append(Date).append("\n");
    if ("".equals(Headers)) {
        strBuff.append(Headers).append(PathAndParameters);
    } else {
        strBuff.append(Headers).append("\n").append(PathAndParameters);
    String StringToSign = strBuff.toString();
    System.out.println("待签名字符串:\n" + StringToSign);
}
- - -  拼接后示例 - - -
uxydqKBMBy6x1siClKEQ6Q==
application/json; charset=UTF-8
/v3/sign-flow/create-by-file

待签名字符串拼接规则

下面介绍下每个字段的提取规则:

  • HTTPMethod :HTTP的请求方法,全部大写,例如:GET、POST。
  • Accept :请求头中的 Accept 值,建议显式设置 Accept Header。当 Accept 为空时,部分 HTTP 框架在未设置 Accept 请求头时会给 Accept 设置默认值为 */*,建议统一设置为 */*。
  • Content-MD5 请求头中 Content-MD5 的值,可为 ""(空字符串), 点击查看 Content-MD5 计算方法
  • Content-Type :请求头中的 Content-Type 值, 可为 ""(空字符串)。
  • Date :请求头中的 Date 值, 可为 ""(空字符串)。时间的描述格式需符合RFC822规范。例如,Thu, 11 Jul 2015 15:33:24 GMT, 点击查看日期时间描述格式说明
  • Headers :开发者选取指定的请求头 Header 参与请求签名计算时,
  • 当开发者需要将一些请求头 Header 也参与请求签名计算时, 请求头 Header 的 Key 需按字典(ASCII码)升序排序 后再按照下面格式进行组合拼接:

HeaderKey1 + ":" + HeaderValue1 + "\n" + HeaderKey2 + ":" + HeaderValue2 + ...

    • 某个Header的Value为空,则使用 HeaderKey+":"+"\n" 参与签名,需要保留Key和英文冒号;
    • 以下Header不参与Header签名计算: X-Tsign-Open-Ca-Signature X-Tsign-Open-Ca-Signature-Headers 、Accept、Content-MD5、Content-Type、Date。
    • 所有参与签名的Header的Key使用英文逗号进行分割后放到请求头Header的 X-Tsign-Open-Ca-Signature-Headers 中;
  • PathAndParameters 这个字段包含 Path 和 Query 的所有参数,简单说就是不包含https://{host}部分的e签宝 API 接口Url,Query 参数对的 Key 需按字典(ASCII码)升序排序 后再按照下面格式进行组合拼接:

Path + "?" + Key1 + "=" + Value1 + "&" + Key2 + "=" + Value2

    • Query 和Form 参数为空时,则直接使用 Path,不需要添加?;
    • 参数的 Value 为空时只保留 Key 参与签名,=不需要再加入签名;
    • Query 和 Form 存在数组参数时(Key相同,Value不同的参数) ,取第一个 Value 参与签名计算;

3.2 计算请求签名值

点击下载demo-EsignGatewaySign.zip

开发者使用 AppSecret(应用密钥) 对待签名字符串进行 HmacSHA256 加密处理,计算得出 请求签名值

计算请求签名值代码示例

/***
	 * 计算请求签名值
	 * @param message 待签名字符串
	 * @param secret  密钥APP KEY
	 * @return HmacSHA256计算后摘要值的Base64编码
	 * @throws Exception 加密过程中的异常信息
	public String doSignatureBase64(String message, String secret) throws Exception {
		String algorithm = "HmacSHA256";
		Mac hmacSha256;
		String digestBase64 = null;
		try {
			hmacSha256 = Mac.getInstance(algorithm);
			byte[] keyBytes = secret.getBytes("UTF-8");
			byte[] messageBytes = message.getBytes("UTF-8");
			hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
			// 使用HmacSHA256对二进制数据消息Bytes计算摘要
			byte[] digestBytes = hmacSha256.doFinal(messageBytes);
			// 把摘要后的结果digestBytes使用Base64进行编码
			digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
		} catch (NoSuchAlgorithmException e) {
			String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
			Exception ex = new Exception(msg);
			ex.initCause(e);
			throw ex;
		} catch (UnsupportedEncodingException e) {
			String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
			Exception ex = new Exception(msg);
			ex.initCause(e);
			throw ex;
		} catch (InvalidKeyException e) {
			String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
			Exception ex = new Exception(msg);
			ex.initCause(e);
			throw ex;
		return digestBase64;
	}

请求签名鉴权完整代码示例

package esign.gateway.demo;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import com.alibaba.fastjson.JSONObject;
public class Test {
  public static void main(String[] args) {
    // 应用ID
    String appId = "743*****";
    // 应用密钥
    String appKey = "106***********43dbcf";
    // e签宝接口调用域名(模拟环境)
    String host = "https://smlopenapi.esign.cn";
    // e签宝接口调用域名(正式环境)
//  String host = "https://openapi.esign.cn";
    // 请求签名鉴权-POST请求
    testPost(appId, appKey, host);
    // 请求签名鉴权-GET请求
//  String signFlowId = "e622498****ebf72d57dbb";
//  testGet(appId, appKey, host, signFlowId);
   * 请求签名鉴权-POST请求
   * @param appId
   * @param appKey
   * @param host
  public static void testPost(String appId, String appKey, String host) {
    // 计算签名拼接的url
    String postUrl = "/v3/files/file-upload-url";
    // 完整的请求地址
    String postAllUrl = host + postUrl;
    try {
      // 构建请求Body体
      JSONObject reqBodyObj = new JSONObject();
      reqBodyObj.put("contentMd5", "KMYh+0qU9/FDXf2TwCGbeg==");
      reqBodyObj.put("contentType", "application/octet-stream");
      reqBodyObj.put("convertToPDF", "true");
      reqBodyObj.put("fileName", "销售合同.docx");
      reqBodyObj.put("fileSize", "81825");
      //reqBodyObj.put("convertToHTML", "false");
      // 请求Body体数据
      String reqBodyData = reqBodyObj.toString();
      // 对请求Body体内的数据计算ContentMD5
      String contentMD5 = doContentMD5(reqBodyData);
      System.out.println("请求body数据:"+reqBodyData);
      System.out.println("body的md5值:"+ contentMD5);
      // 构建待签名字符串
        String method = "POST";
      String accept = "*/*";
      String contentType = "application/json";
      String url = postUrl;
      String date = "";
      String headers = "";
      StringBuffer sb = new StringBuffer();
      sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
          .append(contentType).append("\n").append(date).append("\n");
      if ("".equals(headers)) {
        sb.append(headers).append(url);
      } else {
        sb.append(headers).append("\n").append(url);
      // 构建参与请求签名计算的明文
      String plaintext = sb.toString();
      // 计算请求签名值
      String reqSignature = doSignatureBase64(plaintext, appKey);
      System.out.println("计算请求签名值:"+reqSignature);
      // 获取时间戳(精确到毫秒)
      long timeStamp = timeStamp();
      // 构建请求头
      LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
      header.put("X-Tsign-Open-App-Id", appId);
      header.put("X-Tsign-Open-Auth-Mode", "Signature");
      header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
      header.put("Accept", accept);
      header.put("Content-Type", contentType);
      header.put("X-Tsign-Open-Ca-Signature", reqSignature);
      header.put("Content-MD5", contentMD5);
      // 发送POST请求
      String result = HTTPHelper.sendPOST(postAllUrl, reqBodyData, header, "UTF-8");
      JSONObject resultObj = JSONObject.parseObject(result);
      System.out.println("请求返回信息: " + resultObj.toString());
    } catch (Exception e) {
      e.printStackTrace();
      String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
      System.out.println(msg);
   * 请求签名鉴权-GET请求
   * @param appId
   * @param appKey
   * @param host
  public static void testGet(String appId, String appKey, String host,String signFlowId) {
    // 计算签名拼接的url
    String getUrl = "/v3/sign-flow/"+signFlowId+"/detail";
    // 完整的请求地址
    String getAllUrl = host + getUrl;
    try {
      // GET请求时ContentMD5为""
      String contentMD5 = "";
      // 构建待签名字符串
      String method = "GET";
      String accept = "*/*";
      String contentType = "application/json; charset=UTF-8";
      String url = getUrl;
      String date = "";
      String headers = "";
      StringBuffer sb = new StringBuffer();
      sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
              .append(contentType).append("\n").append(date).append("\n");
      if ("".equals(headers)) {
        sb.append(headers).append(url);
      } else {
        sb.append(headers).append("\n").append(url);
      // 构建参与请求签名计算的明文
      String plaintext = sb.toString();
      // 计算请求签名值
      String reqSignature = doSignatureBase64(plaintext, appKey);
      System.out.println("计算请求签名值:"+ reqSignature);
      // 获取时间戳(精确到毫秒)
      long timeStamp = timeStamp();
      // 构建请求头
      LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
      header.put("X-Tsign-Open-App-Id", appId);
      header.put("X-Tsign-Open-Auth-Mode", "Signature");
      header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
      header.put("Accept", accept);
      header.put("Content-Type", contentType);
      header.put("X-Tsign-Open-Ca-Signature", reqSignature);
      header.put("Content-MD5", contentMD5);
      HashMap<String, Object> query = new HashMap<String, Object>();
     // query.put("orgIDCardNum", "9100*****0004");
     // query.put("orgIDCardType", "CRED_ORG_USCC");
      // 发送GET请求
      String result = HTTPHelper.sendGet(getAllUrl, query, header, "UTF-8");
      JSONObject resultObj = JSONObject.parseObject(result);
      System.out.println("请求返回信息: " + resultObj.toString());
    } catch (Exception e) {
      e.printStackTrace();
      String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
      System.out.println(msg);
   * @param str 待计算的消息
   * @return MD5计算后摘要值的Base64编码(ContentMD5)
   * @throws Exception 加密过程中的异常信息
  public static String doContentMD5(String str) throws Exception {
    byte[] md5Bytes = null;
    MessageDigest md5 = null;
    String contentMD5 = null;
    try {
      md5 = MessageDigest.getInstance("MD5");
      // 计算md5函数
      md5.update(str.getBytes("UTF-8"));
      // 获取文件MD5的二进制数组(128位)
      md5Bytes = md5.digest();
      // 把MD5摘要后的二进制数组md5Bytes使用Base64进行编码(而不是对32位的16进制字符串进行编码)
      contentMD5 = new String(Base64.encodeBase64(md5Bytes), "UTF-8");
    } catch (NoSuchAlgorithmException e) {
      String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
      Exception ex = new Exception(msg);
      ex.initCause(e);
      throw ex;
    } catch (UnsupportedEncodingException e) {
      String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
      Exception ex = new Exception(msg);
      ex.initCause(e);
      throw ex;
    return contentMD5;
   * 计算请求签名值
   * @param message 待计算的消息
   * @param secret 密钥
   * @return HmacSHA256计算后摘要值的Base64编码
   * @throws Exception 加密过程中的异常信息
  public static String doSignatureBase64(String message, String secret) throws Exception {
    String algorithm = "HmacSHA256";
    Mac hmacSha256;
    String digestBase64 = null;
    try {
      hmacSha256 = Mac.getInstance(algorithm);
      byte[] keyBytes = secret.getBytes("UTF-8");
      byte[] messageBytes = message.getBytes("UTF-8");
      hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
      // 使用HmacSHA256对二进制数据消息Bytes计算摘要
      byte[] digestBytes = hmacSha256.doFinal(messageBytes);
      // 把摘要后的结果digestBytes使用Base64进行编码
      digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
    } catch (NoSuchAlgorithmException e) {
      String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
      Exception ex = new Exception(msg);
      ex.initCause(e);
      throw ex;
    } catch (UnsupportedEncodingException e) {
      String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
      Exception ex = new Exception(msg);
      ex.initCause(e);
      throw ex;
    } catch (InvalidKeyException e) {
      String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
      Exception ex = new Exception(msg);
      ex.initCause(e);
      throw ex;
    return digestBase64;
   * 获取时间戳(毫秒级)
   * @return 毫秒级时间戳,如 1578446909000
  public static long timeStamp() {
    long timeStamp = System.currentTimeMillis();
    return timeStamp;

HTTP网络请求代码示例

package esign.gateway.demo;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HTTPHelper {
  // slf4j日志记录器
  private static final Logger LOG = LoggerFactory.getLogger(HTTPHelper.class);
   * 向指定URL发送GET方法的请求
   * @param apiUrl
   * @param data
   * @param projectId
   * @param signature
   * @param encoding
   * @return
   * @throws Exception
  public static String sendGet(String apiUrl, HashMap<String, Object> param,
      LinkedHashMap<String, String> headers, String encoding) throws Exception {
    // 获得响应内容
    String http_RespContent = null;
    HttpURLConnection httpURLConnection = null;
    int http_StatusCode = 0;
    String http_RespMessage = null;
    try {
      // 实际请求完整Url
      StringBuffer fullUrl = new StringBuffer();
      if (null != param) {
        if (0 != param.size()) {
          StringBuffer params = new StringBuffer();
          for (Entry<String, Object> entry : param.entrySet()) {
            params.append(entry.getKey());
            params.append("=");
            params.append(entry.getValue().toString());
            params.append("&");
          if (params.length() > 0) {
            params.deleteCharAt(params.lastIndexOf("&"));
          fullUrl.append(apiUrl).append((params.length() > 0) ? "?" + params.toString() : "");
        } else {
          fullUrl.append(apiUrl);
      } else {
        fullUrl.append(apiUrl);
      LOG.info(">>>> 实际请求Url: " + fullUrl.toString());
      // 建立连接
      URL url = new URL(fullUrl.toString());
      httpURLConnection = (HttpURLConnection) url.openConnection();
      // 需要输出
      httpURLConnection.setDoOutput(true);
      // 需要输入
      httpURLConnection.setDoInput(true);
      // 不允许缓存
      httpURLConnection.setUseCaches(false);
      // HTTP请求方式
      httpURLConnection.setRequestMethod("GET");
      // 设置Headers
      if (null != headers) {
        for (String key : headers.keySet()) {
          httpURLConnection.setRequestProperty(key, headers.get(key));
      // 连接会话
      httpURLConnection.connect();
      // 获得响应状态(HTTP状态码)
      http_StatusCode = httpURLConnection.getResponseCode();
      // 获得响应消息(HTTP状态码描述)
      http_RespMessage = httpURLConnection.getResponseMessage();
      // 获得响应内容
      if (HttpURLConnection.HTTP_OK == http_StatusCode) {
        // 返回响应结果
        http_RespContent = getResponseContent(httpURLConnection);
      } else {
        // 返回非200状态时响应结果
        http_RespContent = getErrorResponseContent(httpURLConnection);
        String msg =
            MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
        LOG.info(msg);
    } catch (UnknownHostException e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (MalformedURLException e) {
      String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (IOException e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (Exception e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } finally {
      if (null != httpURLConnection) {
        httpURLConnection.disconnect();
    return http_RespContent;
   * 向指定URL发送POST方法的请求
   * @param apiUrl
   * @param data
   * @param projectId
   * @param signature
   * @param encoding
   * @return
   * @throws Exception
  public static String sendPOST(String apiUrl, String data, LinkedHashMap<String, String> headers,
      String encoding) throws Exception {
    // 获得响应内容
    String http_RespContent = null;
    HttpURLConnection httpURLConnection = null;
    int http_StatusCode = 0;
    String http_RespMessage = null;
    try {
      // 建立连接
      URL url = new URL(apiUrl);
      httpURLConnection = (HttpURLConnection) url.openConnection();
      // 需要输出
      httpURLConnection.setDoOutput(true);
      // 需要输入
      httpURLConnection.setDoInput(true);
      // 不允许缓存
      httpURLConnection.setUseCaches(false);
      // HTTP请求方式
      httpURLConnection.setRequestMethod("POST");
      // 设置Headers
      if (null != headers) {
        for (String key : headers.keySet()) {
          httpURLConnection.setRequestProperty(key, headers.get(key));
      // 连接会话
      httpURLConnection.connect();
      // 建立输入流,向指向的URL传入参数
      DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
      // 设置请求参数
      dos.write(data.getBytes(encoding));
      dos.flush();
      dos.close();
      // 获得响应状态(HTTP状态码)
      http_StatusCode = httpURLConnection.getResponseCode();
      // 获得响应消息(HTTP状态码描述)
      http_RespMessage = httpURLConnection.getResponseMessage();
      // 获得响应内容
      if (HttpURLConnection.HTTP_OK == http_StatusCode) {
        // 返回响应结果
        http_RespContent = getResponseContent(httpURLConnection);
      } else {
        // 返回非200状态时响应结果
        http_RespContent = getErrorResponseContent(httpURLConnection);
        String msg =
            MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
        LOG.info(msg);
    } catch (UnknownHostException e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (MalformedURLException e) {
      String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (IOException e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } catch (Exception e) {
      String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
      Exception ex = new Exception(message);
      ex.initCause(e);
      throw ex;
    } finally {
      if (null != httpURLConnection) {
        httpURLConnection.disconnect();
    return http_RespContent;
   * 读取HttpResponse响应内容
   * @param httpURLConnection
   * @return
   * @throws UnsupportedEncodingException
   * @throws IOException
  private static String getResponseContent(HttpURLConnection httpURLConnection)
      throws UnsupportedEncodingException, IOException {
    StringBuffer contentBuffer = null;
    BufferedReader responseReader = null;
    try {
      contentBuffer = new StringBuffer();
      String readLine = null;
      responseReader =
          new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8"));
      while ((readLine = responseReader.readLine()) != null) {
        contentBuffer.append(readLine);
    } finally {
      if (null != responseReader) {
        responseReader.close();
    return contentBuffer.toString();
   * 读取HttpResponse响应内容
   * @param httpURLConnection
   * @return
   * @throws UnsupportedEncodingException
   * @throws IOException
  private static String getErrorResponseContent(HttpURLConnection httpURLConnection)
      throws UnsupportedEncodingException, IOException {
    StringBuffer contentBuffer = null;
    BufferedReader responseReader = null;
    try {
      contentBuffer = new StringBuffer();
      String readLine = null;
      responseReader =
          new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8"));
      while ((readLine = responseReader.readLine()) != null) {
        contentBuffer.append(readLine);
    } finally {
      if (null != responseReader) {
        responseReader.close();