最近項目有用到騰訊雲的身份識別介面,話不多說,直接上代碼: 開始的時候,使用了HTTP的POST這種請求方式進行調用,但後面發現這種請求方式有Bug,一旦用戶上傳的圖片尺寸太大(跟圖片大小沒關係,主要是尺寸),請求騰訊的API就會返回下麵這個錯誤(PS:因為我這邊使用的是OCR身份證識別API,如果 ...
最近項目有用到騰訊雲的身份識別介面,話不多說,直接上代碼:
1 private void IDCardVerification(HttpContext context) 2 { 3 4 string imgStr = context.Request["ImageBase64"]; 5 if (!string.IsNullOrEmpty(imgStr)) 6 { 7 try 8 { 9 //請求地址 10 string settingUrl = ConfigurationManager.AppSettings.Get("IDCardVerifUrl"); 11 //應用ID 12 string secretId = ConfigurationManager.AppSettings.Get("TcCloudSecretId"); 13 //應用key 14 string secretKey = ConfigurationManager.AppSettings.Get("TcCloudSecretKey"); 15 //時間戳 16 string timesTamp = GetTimeStamp(); 17 //Nonce 18 var nonce = new Random().Next(10000, 99999); 19 //拼接參數 20 string paramsStr = string.Format(@"Action=IDCardOCR&CardSide=FRONT&ImageBase64={0}&Nonce={1}&Region=ap-guangzhou&SecretId={2}&SignatureMethod=HmacSHA1&Timestamp={3}&Version=2018-11-19", 21 imgStr, nonce, secretId, timesTamp); 22 //生成簽名參數 23 string requestText = "POST" + settingUrl.Replace("https://", "") + "?" + paramsStr; 24 //獲得請求簽名 25 string signText = GetHmacSha1Sign(secretKey, requestText); 26 //這裡一定要進行URL編碼,不然調用API會報錯 27 signText = HttpUtility.UrlEncode(signText, Encoding.UTF8); 28 imgStr = HttpUtility.UrlEncode(imgStr, Encoding.UTF8); 29 paramsStr = string.Format(@"Action=IDCardOCR&CardSide=FRONT&ImageBase64={0}&Nonce={1}&Region=ap-guangzhou&SecretId={2}&Signature={3}&SignatureMethod=HmacSHA1&Timestamp={4}&Version=2018-11-19", 30 imgStr, nonce, secretId, signText, timesTamp); 31 //請求騰訊API,返回身份證信息 32 string resultStr = Globals.SendRequest(settingUrl, paramsStr); 33 var idCard = new JavaScriptSerializer().Deserialize<IDCardVerif>(resultStr); 34 var iDCardInfo = idCard.Response; 35 if (iDCardInfo.Error != null) 36 { 37 context.Response.Write("{\"Status\":\"fail\",\"errorMsg\":\"身份證識別出錯: " + iDCardInfo.Error.Message + " \"}"); 38 } 39 else 40 { 41 var result = new { Status = "success", data = new { iDCardInfo.name, iDCardInfo.Sex, iDCardInfo.Nation, iDCardInfo.IdNum, iDCardInfo.Address, iDCardInfo.Birth } }; 42 context.Response.Write(new JavaScriptSerializer().Serialize(result)); 43 } 44 } 45 catch (Exception ex) 46 { 47 context.Response.Write("{\"Status\":\"fail\",\"errorMsg\":\"請求介面出錯 \"}"); 48 } 49 } 50 else 51 { 52 context.Response.Write("{\"Status\":\"fail\",\"errorMsg\":\"請選擇上傳的圖片!\"}"); 53 } 54 55 56 } 57 58 59 /// <summary> 60 /// 獲取時間戳 61 /// </summary> 62 /// <returns></returns> 63 public static string GetTimeStamp() 64 { 65 TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); 66 return Convert.ToInt64(ts.TotalSeconds).ToString(); 67 } 68 69 /// <summary> 70 /// HMAC-SHA1加密返回簽名 71 /// </summary> 72 /// <param name="secret">密鑰</param> 73 /// <param name="strOrgData">源文</param> 74 /// <returns></returns> 75 public static string GetHmacSha1Sign(string secret, string strOrgData) 76 { 77 var hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(secret)); 78 var dataBuffer = Encoding.UTF8.GetBytes(strOrgData); 79 var hashBytes = hmacsha1.ComputeHash(dataBuffer); 80 return Convert.ToBase64String(hashBytes); 81 } 82 83 public static string SendRequest(string url, string completeUrl) 84 { 85 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 86 request.Method = "POST"; 87 request.ContentType = "application/x-www-form-urlencoded"; 88 request.ProtocolVersion = HttpVersion.Version10; 89 request.Host = url.Replace("https://", "").Replace("/", ""); 90 byte[] data = Encoding.UTF8.GetBytes(completeUrl); 91 request.ContentLength = data.Length; 92 Stream newStream = request.GetRequestStream(); 93 newStream.Write(data, 0, data.Length); 94 newStream.Close(); 95 HttpWebResponse response = null; 96 string content; 97 try 98 { 99 response = (HttpWebResponse)request.GetResponse(); 100 StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); 101 content = reader.ReadToEnd(); 102 } 103 catch (WebException e) 104 { 105 response = (HttpWebResponse)e.Response; 106 using (Stream errData = response.GetResponseStream()) 107 { 108 using (StreamReader reader = new StreamReader(errData)) 109 { 110 content = reader.ReadToEnd(); 111 } 112 } 113 } 114 return content; 115 }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Hmeshop.Entities { public class IDCardVerif { public IDCardVerifInfo Response { get; set; } } public class IDCardVerifInfo { /// <summary> /// 姓名 /// </summary> public string name { get; set; } /// <summary> /// 性別 /// </summary> public string Sex { get; set; } /// <summary> /// 民族 /// </summary> public string Nation { get; set; } /// <summary> /// 生日 /// </summary> public string Birth { get; set; } /// <summary> /// 地址 /// </summary> public string Address { get; set; } /// <summary> /// 身份證號 /// </summary> public string IdNum { get; set; } /// <summary> /// 發證機關 /// </summary> public string Authority { get; set; } /// <summary> /// 證件有效期 /// </summary> public string ValidDate { get; set; } /// <summary> /// 擴展信息 /// </summary> public string AdvancedInfo { get; set; } /// <summary> /// 唯一請求 ID,每次請求都會返回。定位問題時需要提供該次請求的 RequestId。 /// </summary> public string RequestId { get; set; } /// <summary> /// 錯誤信息,有則返回,沒有則為空 /// </summary> public ErrorInfo Error { get; set; } } public class ErrorInfo { public string Code { get; set; } public string Message { get; set; } } }
開始的時候,使用了HTTP的POST這種請求方式進行調用,但後面發現這種請求方式有Bug,一旦用戶上傳的圖片尺寸太大(跟圖片大小沒關係,主要是尺寸),請求騰訊的API就會返回下麵這個錯誤(PS:因為我這邊使用的是OCR身份證識別API,如果不涉及圖片文件的話,可以使用我上面的調用方式):
根據圖上的錯誤信息可知,需要用到TC3-HMAC-SHA256這個簽名演算法,So,沒辦法,我們只能用騰訊的SDK來調用了,SDK直接在VS的Nuget里下載就好了,在GitHub下載源碼進行編譯引用也行
下麵貼騰訊官方SDK調用代碼:
1 private void IDCardVerificationBySDK(HttpContext context) 2 { 3 string imgStr = context.Request["ImageBase64"]; 4 try 5 { 6 if (!string.IsNullOrEmpty(imgStr)) 7 { 8 string res = string.Empty; 9 10 Action<string> action = t => 11 { 12 res = GetOCRMsg(imgStr); 13 }; 14 IAsyncResult asyncResult = action.BeginInvoke("調用騰訊雲身份證識別", null, null); 15 asyncResult.AsyncWaitHandle.WaitOne(); 16 if (res.Contains("message")) 17 { 18 context.Response.Write("{\"Status\":\"fail\",\"errorMsg\":\"" + res.Split(new string[] { "message:" }, StringSplitOptions.None)[1] + "\"}"); 19 } 20 else 21 { 22 IDCardOCRResponse resp = JsonConvert.DeserializeObject<IDCardOCRResponse>(res); 23 var result = new { Status = "success", data = resp }; 24 context.Response.Write(JsonConvert.SerializeObject(result)); 25 } 26 } 27 else 28 { 29 context.Response.Write("{\"Status\":\"fail\",\"errorMsg\":\"請選擇上傳的圖片!\"}"); 30 } 31 } 32 catch(Exception ex) 33 { 34 Globals.Debuglog("調用介面出錯:" + ex.StackTrace, "Tentent_IDCardVerif.txt"); 35 } 36 37 } 38 39 40 private string GetOCRMsg(string imgStr) 41 { 42 try 43 { 44 Credential cred = new Credential 45 { 46 SecretId = ConfigurationManager.AppSettings.Get("TcCloudSecretId"), 47 SecretKey = ConfigurationManager.AppSettings.Get("TcCloudSecretKey") 48 }; 49 50 ClientProfile clientProfile = new ClientProfile 51 { 52 SignMethod = ClientProfile.SIGN_TC3SHA256 53 }; 54 HttpProfile httpProfile = new HttpProfile(); 55 httpProfile.Endpoint = ("ocr.tencentcloudapi.com"); 56 httpProfile.ReqMethod = "POST"; 57 httpProfile.Timeout = 10; // 請求連接超時時間,單位為秒(預設60秒) 58 clientProfile.HttpProfile = httpProfile; 59 OcrClient client = new OcrClient(cred, "ap-guangzhou", clientProfile); 60 IDCardOCRRequest req = new IDCardOCRRequest(); 61 string strParams = "{\"ImageBase64\":\""+ imgStr + "\",\"CardSide\":\"FRONT\",\"ImageUrl\":\"\",\"Config\":\"\"}"; 62 Globals.Debuglog("strParams: " + strParams, "Tentent_IDCardVerif.txt"); 63 req = JsonConvert.DeserializeObject<IDCardOCRRequest>(strParams); 64 IDCardOCRResponse resp = client.IDCardOCR(req). 65 ConfigureAwait(false).GetAwaiter().GetResult(); 66 return AbstractModel.ToJsonString(resp); 67 } 68 catch (Exception e) 69 { 70 Globals.Debuglog("請求介面出錯:" + e.StackTrace, "Tentent_IDCardVerif.txt"); 71 return e.Message.ToString(); 72 } 73 } 74
這裡要註意的是,一定要使用非同步請求的方式進行調用! 不然直接調用的話,執行到:
ConfigureAwait(false).GetAwaiter().GetResult();
這一步會沒有任何響應,程式陷入假死狀態,博主就是在這裡踩了坑,嘗試了多次才發現這個問題,真是坑爹啊- -!
好了,就先說到這裡了,這是本人在博客園的處女blog,希望給各位有需要的人一點幫助哈~