当前位置:主页 > 查看内容

内网环境请求语音识别-一句话识别

发布时间:2021-07-29 00:00| 位朋友查看

简介:应用场景 公司项目环境是内网,无法直连公网,需要通过代理服务器向腾讯云发起接口请求,请问这个过程应该怎样实现? 分析及演示过程 腾讯云云API3.0有两种调用方式:SDK和自主鉴权,SDK封装了签名计算过程和网络通信过程而自主鉴权需要我们参考鉴权文档和对……

应用场景

公司项目环境是内网,无法直连公网,需要通过代理服务器向腾讯云发起接口请求,请问这个过程应该怎样实现?

分析及演示过程

腾讯云云API3.0有两种调用方式:SDK和自主鉴权,SDK封装了签名计算过程和网络通信过程而自主鉴权需要我们参考鉴权文档和对应的接口文档自行封装请求方法,这里演示两种调用方式下的代理配置方式,在两种演示之前,我们都需要完成Nginx的安装,保证Nginx处于正常运行状态

第一步:完成Nginx安装并保证其正常运行

代理服务器系统环境

lsb_release -a

代理软件版本

nginx -v

代理软件运行状态

systemctl status nginx

若未运行,可以通过如下命令运行

systemctl start nginx

第二步:演示

演示一:SDK代理配置方式,这里以tencentcloud-sdk-java为例

由于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后,测试效果

演示二:自主鉴权代理配置方式,还是以Java语言为示例

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接口


本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐