公司项目环境是内网,无法直连公网,需要通过代理服务器向腾讯云发起接口请求,请问这个过程应该怎样实现?
腾讯云云API3.0有两种调用方式:SDK和自主鉴权,SDK封装了签名计算过程和网络通信过程而自主鉴权需要我们参考鉴权文档和对应的接口文档自行封装请求方法,这里演示两种调用方式下的代理配置方式,在两种演示之前,我们都需要完成Nginx的安装,保证Nginx处于正常运行状态
代理服务器系统环境
lsb_release -a
代理软件版本
nginx -v
代理软件运行状态
systemctl status nginx
若未运行,可以通过如下命令运行
systemctl start nginx
由于SDK只能支持HTTP代理,所以我这里直接进入Nginx的默认配置文件目录并配置默认的80端口的代理参数
cd /etc/nginx/conf.d
vi default.conf
配置内容如下
server { listen 80; server_name asr.tencentcloudapi.com; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { proxy_pass https://asr.tencentcloudapi.com/; root html; index index.html index.htm; proxy_set_header Host $http_host; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
上述配置的关键语句是 listen 80; server_name asr.tencentcloudapi.com; proxy_pass https://asr.tencentcloudapi.com/;
配置完成后重启nginx服务
systemctl restart nginx
检查nginx运行状态
systemctl status nginx
接下来,配置内网服务器部分,先将内网机器的hosts配置如下内容
192.168.2.52 asr.tencentcloudapi.com
我这里以Win10 PC的hosts配置为例
其中192.168.2.52是内网业务机器的内网IP,asr.tencentcloudapi.com是腾讯云云产品的接口域名,内网解析配置好之后,去配置代码部分,SDK下的接口Demo获取方式可以通过Api Explorer获取,这个不做过多解释,配置代理后的代码示例如下
import com.tencentcloudapi.common.Credential; import com.tencentcloudapi.common.profile.ClientProfile; import com.tencentcloudapi.common.profile.HttpProfile; import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.asr.v20190614.AsrClient; import com.tencentcloudapi.asr.v20190614.models.*; public class SentenceRecognition { public static void main(String [] args) { try{ // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 Credential cred = new Credential("SecretId", "SecretKey"); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); httpProfile.setProtocol("http://"); //http 协议 httpProfile.setEndpoint("asr.tencentcloudapi.com"); // 实例化一个client选项,可选的,没有特殊需求可以跳过 ClientProfile clientProfile = new ClientProfile(); clientProfile.setHttpProfile(httpProfile); // 实例化要请求产品的client对象,clientProfile是可选的 AsrClient client = new AsrClient(cred, "", clientProfile); // 实例化一个请求对象,每个接口都会对应一个request对象 SentenceRecognitionRequest req = new SentenceRecognitionRequest(); // 返回的resp是一个SentenceRecognitionResponse的实例,与请求对象对应 SentenceRecognitionResponse resp = client.SentenceRecognition(req); // 输出json格式的字符串回包 System.out.println(SentenceRecognitionResponse.toJsonString(resp)); } catch (TencentCloudSDKException e) { System.out.println(e.toString()); } } }
关键语句只有一句:httpProfile.setProtocol("http://");//http 协议
这里的原理就是,SDK默认是向域名asr.tencentcloudapi.com发起请求的,我们将域名 asr.tencentcloudapi.com的解析强制配置到代理机器的IP后,就可以实现转发了,然后测试一下效果
反向测试,我们将hosts的解析修改为一个不存在的IP后,测试效果
Nginx代理软件配置文件内容如下
编辑配置文件命令
vi /etc/nginx/nginx.conf
user nginx; worker_processes 1; error_log /var/log/nginx/error_log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http{ include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 64; #gzip on; include /etc/nginx/conf.d/*.conf; server{ listen 443 ssl; server_name tencent.cdhwdl.com; #charset koi8-r; ssl_certificate /etc/nginx/ssl_key/ten.crt; ssl_certificate_key /etc/nginx/ssl_key/ten.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; #access_log logs/host.access.log main; location / { proxy_pass https://asr.tencentcloudapi.com/; root html; index index.html index.htm; } } }
其中,下图红框部分是代理服务器的域名的443端口访问配置
/etc/nginx/conf.d/*.conf中配置的是默认的80端口访问配置
cd /etc/nginx/conf.d/ ls
cat default.conf
80端口配置文件在/etc/nginx/conf.d/ default.conf中,配置文件参考内容如下
server { listen 80; server_name tencent.cdhwdl.com; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { proxy_pass https://asr.tencentcloudapi.com/; root html; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
这里我们的代理服务器域名是tencent.cdhwdl.com,代理服务器的IP是192.168.2.52,我们模拟的内网业务环境是一台PC,IP是192.168.2.104,我们配置一下hosts解析,将tencent.cdhwdl.com强制解析到192.168.2.52
然后通过API Explorer生成一句话识别的请求报文
通过postman向代理服务器域名发起请求
接下来我们通过Java程序发起代理请求
反向验证
package tencentcloudapi; import com.google.gson.Gson; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.*; import java.security.MessageDigest; import java.text.SimpleDateFormat; import java.util.*; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; public class SentenceRecognition { private static String SecretId = ""; private static String SecretKey = ""; private static String Url = "https://tencent.cdhwdl.com"; //规范请求串 private static String HTTPRequestMethod = "POST"; private static String CanonicalURI = "/"; private static String CanonicalQueryString = ""; private static String CanonicalHeaders = "content-type:application/json; charset=utf-8\nhost:asr.tencentcloudapi.com\n"; private static String SignedHeaders = "content-type;host";//参与签名的头部信息 //签名字符串 private static String Algorithm = "TC3-HMAC-SHA256"; private static String Service = "asr"; private static String Stop = "tc3_request"; //版本 public static String Version = "2019-06-14"; public static String Region = "ap-beijing"; /*** * 示例名片请求方法 * @param args */ public static void main(String [] args) { Map<String, Object> params = new HashMap<>(); params.put("ProjectId", 0); params.put("SubServiceType", 2); params.put("EngSerViceType", "8k_zh"); params.put("SourceType", 0); params.put("Url", "https://lifedata.oss-cn-beijing.aliyuncs.com/test.mp3?OSSAccessKeyId=LTAI5tGiSx3mDVBVjZqQb4bj&Expires=1626687604&Signature=EK8YpzhWfinWEMX5KiRIFTKQvgw%3D"); params.put("VoiceFormat", "mp3"); params.put("UsrAudioKey", "abc"); Gson gson = new Gson(); String param = gson.toJson(params); //发送请求 本地封装的https 请求 String response = getAuthTC3("SentenceRecognition", param, Version); //打印请求数据 System.out.println(response); } /** * v3鉴权 * @param action 方法名 * @param paramJson json化的参数 * @param version 版本号 2019-06-14 * @return */ public static String getAuthTC3(String action, String paramJson, String version){ try{ String hashedRequestPayload = HashEncryption(paramJson); String CanonicalRequest = HTTPRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + hashedRequestPayload; //时间戳 Date date = new Date(); //微秒->秒 String timestamp = String.valueOf(date.getTime() / 1000); //格林威治时间转化 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); formatter.setTimeZone(TimeZone.getTimeZone("GMT+0")); String dateString = formatter.format(date.getTime()); //签名字符串 String credentialScope = dateString + "/" + Service + "/" + Stop; String hashedCanonicalRequest = HashEncryption(CanonicalRequest); String stringToSign = Algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest; //计算签名 byte[] secretDate = HashHmacSha256Encryption(("TC3" + SecretKey).getBytes("UTF-8"), dateString); byte[] secretService = HashHmacSha256Encryption(secretDate, Service); byte[] secretSigning = HashHmacSha256Encryption(secretService, Stop); //签名字符串 byte[] signatureHmacSHA256 = HashHmacSha256Encryption(secretSigning, stringToSign); StringBuilder builder = new StringBuilder(); for (byte b : signatureHmacSHA256) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } builder.append(hex); } String signature = builder.toString().toLowerCase(); //组装签名字符串 String authorization = Algorithm + ' ' + "Credential=" + SecretId + '/' + credentialScope + ", " + "SignedHeaders=" + SignedHeaders + ", " + "Signature=" + signature; //创建header 头部 Map<String, String> headers = new HashMap<>(); headers.put("Authorization", authorization); headers.put("Host", "asr.tencentcloudapi.com"); headers.put("Content-Type", "application/json; charset=utf-8"); headers.put("X-TC-Action", action); headers.put("X-TC-Version", version); headers.put("X-TC-Timestamp", timestamp); headers.put("X-TC-Region", Region); //request 请求 String response = resquestPostData(Url, paramJson, headers); return response; }catch(Exception e){ return e.getMessage(); } } /* * Function : 发送Post请求到服务器 * Param : params请求体内容,encode编码格式 */ public static String resquestPostData(String strUrlPath, String data, Map<String, String> headers) { try { URL url = new URL(strUrlPath); HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection(); httpURLConnection.setConnectTimeout(3000); //设置连接超时时间 httpURLConnection.setDoInput(true); //打开输入流,以便从服务器获取数据 httpURLConnection.setDoOutput(true); //打开输出流,以便向服务器提交数据 httpURLConnection.setRequestMethod("POST"); //设置以Post方式提交数据 httpURLConnection.setUseCaches(false); //使用Post方式不能使用缓存 //设置header if (headers.isEmpty()) { //设置请求体的类型是文本类型 httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8"); } else { for (Map.Entry<String, String> entry : headers.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); httpURLConnection.setRequestProperty(key, value); } } //设置请求体的长度 httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length())); //获得输出流,向服务器写入数据 if (data != null) { byte[] writebytes = data.getBytes(); // 设置文件长度 OutputStream outputStream = httpURLConnection.getOutputStream(); outputStream.write(data.getBytes()); outputStream.flush(); } int response = httpURLConnection.getResponseCode(); //获得服务器的响应码 if(response == HttpURLConnection.HTTP_OK) { InputStream inptStream = httpURLConnection.getInputStream(); return dealResponseResult(inptStream); //处理服务器的响应结果 } } catch (IOException e) { return "err: " + e.getMessage().toString(); } return "-1"; } /* * Function : 封装请求体信息 * Param : params请求体内容,encode编码格式 */ public static StringBuffer getRequestData(Map<String, String> params, String encode) { StringBuffer stringBuffer = new StringBuffer(); //存储封装好的请求体信息 try { for(Map.Entry<String, String> entry : params.entrySet()) { stringBuffer.append(entry.getKey()) .append("=") .append(URLEncoder.encode(entry.getValue(), encode)) .append("&"); } stringBuffer.deleteCharAt(stringBuffer.length() - 1); //删除最后的一个"&" } catch (Exception e) { e.printStackTrace(); } return stringBuffer; } /* * Function : 处理服务器的响应结果(将输入流转化成字符串) * Param : inputStream服务器的响应输入流 */ public static String dealResponseResult(InputStream inputStream) { String resultData = null; //存储处理结果 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; try { while((len = inputStream.read(data)) != -1) { byteArrayOutputStream.write(data, 0, len); } } catch (IOException e) { e.printStackTrace(); } resultData = new String(byteArrayOutputStream.toByteArray()); return resultData; } /** * */ private static String HashEncryption(String s) throws Exception { MessageDigest sha = MessageDigest.getInstance("SHA-256"); sha.update(s.getBytes()); //替换java DatatypeConverter.printHexBinary(d).toLowerCase() StringBuilder builder = new StringBuilder(); for (byte b : sha.digest()) { String hex = Integer.toHexString(b & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } builder.append(hex); } return builder.toString().toLowerCase(); } private static byte[] HashHmacSha256Encryption(byte[] key, String msg) throws Exception { Mac mac = Mac.getInstance("HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm()); mac.init(secretKeySpec); return mac.doFinal(msg.getBytes("UTF-8")); } }
1)自主鉴权方式无论是通过本地hosts到代理服务器或者通过代理服务器IP都可以实现代理转发请求到腾讯云,SDK方式由于需要对齐SDK的行为,所以只能支持HTTP协议且必须配置hosts 2)此方法适用于平台的所有API3.0接口
很长时间没有更新原创文章了,但是还一直在思考和沉淀当中,后面公众号会更频繁...
定义 this是函数运行时自动生成的内部对象,即调用函数的那个对象。(不一定很准...
2020年对于云计算行业来说是突破性的一年,因为公共云供应商增加了收入,而疫情...
查看表结构,sbtest1有主键、k_1二级索引、i_c二级索引 CREATE TABLE `sbtest1` ...
最近,DevOps的采用导致了企业计算的重大转变。除无服务器计算,动态配置和即付...
9月17日,2020云栖大会上,阿里云正式发布工业大脑3.0。 阿里云智能资深产品专家...
在TOP云(zuntop.com)科技租赁过服务器的站长都知道独立服务器在价格上比VPS主...
一、PostgreSQL行业位置 一 行业位置 首先我们看一看RDS PostgreSQL在整个行业当...
本文转载自网络,原文链接:https://mp.weixin.qq.com/s/vlOUg46B5bcmToX-fjavJQ...
中国最?好的一朵云飘进了华瑞银行。阿里云将进一步助力华瑞银行All in Cloud。 -...