让android支持https访问银联后台,测试成功

简介: 让android支持https访问银联后台,测试成功

根据XX公网前置接入规范,XX后台支持公网接入。但必须走https协议加密传输。


java很强大,在java上调用http接口以及解析json之类的应该很容易,有很多现成的接口和第三方库如httpclinet,okhttp,volley,retrofit等。


但是,XX的这套接口涉及到https加密传输,需加载本地公钥证书,以及定制http协议报文头,并且post的是16进制数据。


网上查资料,大多都是讲如何post提交json的,以及如何上传二进制图片的等内容。没找到如何提交二进制流的。


于是自己摸索了吧,接口通了。在此总结下,非专业andorid出身,代码有点乱。但要点就那几个。


使用的是retrofit.


要实现的协议格式如下:


POST/mjc/webtrans/VPB_lb HTTP/1.1
HOST:xxxxxxxx:xxxxx
User-Agent: Donjin Http0.1
Cache-Control: no-cache
Content-Type:x-XX-XXXX/x-XX
Accept: */*
Content-Length: xx
00 XX XX 00 0X 00 00 XX XX 00 XX XX XX XX00 00 20 00 00 00 c0 00 16 00 00 01 31 30 30 30 30


要点1,自定义http报文头,这个很简单了,举例如下:


@Headers({"User-Agent: Donjin Http 0.1","Cache-Control: no-cache","Content-Type: x-xxx","Accept-Encoding: *","Content-Length: xx"})//需要添加头
   // @Multipart
    @POST("/")
    Call<LoginResult> postData(@Body  RequestBody bodyhex);


需要注意的是,content-lenth这个别按上面的写固定了,这个是根据要提交的16进制数据来的。他不是一个固定值。


提交的数据内容直接传参 @Body RequestBody bodyhex


传的参数怎么处理,让他能够以16进制post呢?


如下,重新overrite RequestBody中的writeto方法和contenlenth放法,注意,必须得有contenlenth方法,否则会出错,不知道你post的数据有多少。


示例如下:


class DataBean {
    public byte[] data;
    public String DA = "00000000000000c0006300011000000010030002953657175656e6365204343131390003303120";//要发送的16进制数据的字符串形式
    public RequestBody bodyhex;
    public DataBean()
    {
        data = hexStringToBytes(DA);//转为hex 16进制
        bodyhex =  new RequestBody() {
            @Override
            public MediaType contentType() {
                return null;
            }
            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.write(data);
            }
            @Override
            public long contentLength() {
                return data.length;
            }
        };
    };
}


还有一个比较重要的地方就是加载https的本地公钥证书啦


/**
 * 通过okhttpClient来设置证书
 * @param clientBuilder OKhttpClient.builder
 * @param certificates 读取证书的InputStream
 */
public static void setCertificates(OkHttpClient.Builder clientBuilder, InputStream... certificates) {
    try {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        int index = 0;
        for (InputStream certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificateFactory
                    .generateCertificate(certificate));
            try {
                if (certificate != null)
                    certificate.close();
            } catch (IOException e) {
            }
        }
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        clientBuilder.sslSocketFactory(sslSocketFactory,trustManager);
    } catch (Exception e) {
        e.printStackTrace();
    }
}


public  static OkHttpClient getOkHttpSingletonInstance( Context ct) {
    mContext = ct;
    if (okHttpClient == null) {
        synchronized (OkHttpClient.class) {
            if (okHttpClient == null) {
                okHttpClient = new OkHttpClient();
                //设置合理的超时
                OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
                        .readTimeout(3, TimeUnit.SECONDS)
                        .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) //设置连接超时 30秒
                        .writeTimeout(3, TimeUnit.MINUTES)
                        //.addInterceptor(new LoggingInterceptor())//添加请求拦截
                        .addNetworkInterceptor(
                                new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS))
                        .hostnameVerifier(new HostnameVerifier() {
                            @Override
                            public boolean verify(String hostname, SSLSession session) {
                                return true;
                            }
                        })
                        //.sslSocketFactory(sslParams.sSLSocketFactory,sslParams.trustManager)
                        .retryOnConnectionFailure(true);
                //InputStream in = new InputStream()
                try {
                    //AssetManager assetManager =  AssetManager.class.newInstance();
                    InputStream is = MyAppcation.getInstance().getAssets().open("UP.pem");
                    OkHttp3Utils.setCertificates( httpBuilder,is);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                okHttpClient = httpBuilder.build();
            }
        }
    }
    return okHttpClient;
}


完成以上这些,就够了。能够实现一开始的要求了。最后完善下接口,在自定义一个


ConverterFactory


对应答的报文解析就完整了。


测试结果如下:


06-15 03:37:45.183 4061-4099/com.example.yang.myapplication D/OkHttp: Connection: Keep-Alive
    --> END POST
06-15 03:37:45.585 4061-4099/com.example.yang.myapplication D/OkHttp: <-- 200 OK https://xx.xx.1xx.xx:xxx0/ (400ms)
06-15 03:37:45.589 4061-4099/com.example.yang.myapplication D/OkHttp: Allow: POST, PUT
06-15 03:37:45.590 4061-4099/com.example.yang.myapplication D/OkHttp: Content-Type: x-ISO-xxx/x-xx
06-15 03:37:45.591 4061-4099/com.example.yang.myapplication D/OkHttp: Date: Fri, 15 Jun 2018 03:39:44 GMT
06-15 03:37:45.592 4061-4099/com.example.yang.myapplication D/OkHttp: Content-Length: 112
    Server: Access-Guard-1000-Software/1.0
06-15 03:37:45.603 4061-4099/com.example.yang.myapplication D/OkHttp: Connection: close
06-15 03:37:45.604 4061-4099/com.example.yang.myapplication D/OkHttp: <-- END HTTP
06-15 03:37:45.633 4061-4099/com.example.yang.myapplication 
D/respond:: 00XXXXXXXXXXXXXXXXXXXXXXXXXXX600000001003000296f3136333135305358582d3443333034313139
06-15 03:37:45.704 4061-4061/com.example.yang.myapplication D/AA: 成功
Response{protocol=http/1.1, code=200, message=OK, url=https://XXXXXXXX;XXX/}
D/OkHttp: --> POST https://1xx.xx.xx.xx:xxxx/ http/1.1
          Content-Type: x-ISO-TPDU/x-auth
D/OkHttp: Content-Length: 89
          User-Agent: Donjin Http 0.1
          Cache-Control: no-cache
          Accept-Encoding: *
D/OkHttp: Host: xxx.xxx.xxx.xx:xxxx
          Connection: Keep-Alive
          --> END POST
D/OkHttp: <-- 200 OK https://xxx.xxx.xxx.xx:xxxx/ (421ms)
D/OkHttp: Allow: POST, PUT
          Content-Type: x-ISO-TPDU/x-auth
          Date: Sat, 30 Jun 2018 09:58:41 GMT
D/OkHttp: Content-Length: 123
D/OkHttp: Server: Access-Guard-1000-Software/1.0
          Connection: close
          <-- END HTTP
D/AA: 成功
      Response{protocol=http/1.1, code=200, message=OK, url=https://xxxxxxxx:xxxxx/}
D/respondAA:: 007960000005016131003111080810003800010ac0001400000117563506300800094900313735363335353837303233303037333738323231343839383431313334313331303031340011000007500030004050bc9eb4774a92544c29dad2c764150bb93eba92d9f11a222efa9c2300000000000000002b580802
I/System.out: 开始解析...
I/System.out: ->ok 解析成功!
I/System.out: pinkey:b1a7ab3cb49c9757390f39a19ce71ae7
I/System.out: <-Er PIK错误


相关文章
|
2月前
|
监控 安全 Android开发
【新手必读】Airtest测试Android手机常见的设置问题
【新手必读】Airtest测试Android手机常见的设置问题
|
2月前
|
弹性计算 应用服务中间件 Apache
ECS配置问题之输入ip无法访问如何解决?
ECS配置指的是对阿里云Elastic Compute Service(弹性计算服务)实例的硬件和软件资源进行设置的过程;本合集将详述如何选择合适的ECS配置、调整资源配比以及优化实例性能,以满足不同应用场景的需求。
|
4天前
|
存储 Java API
Android系统 文件访问权限笔记
Android系统 文件访问权限笔记
35 1
|
4天前
|
运维 网络协议 Linux
Android 双网卡配置为连接到Android主机的PC提供外网访问(1)
Android 双网卡配置为连接到Android主机的PC提供外网访问(1)
16 0
|
5天前
|
Java API Android开发
Android 11 修改libcore Cipher AS测试
Android 11 修改libcore Cipher AS测试
13 1
|
9天前
|
应用服务中间件 网络安全 Apache
解决跨域和https不能访问的问题
【4月更文挑战第10天】解决跨域和https不能访问的问题
42 2
解决跨域和https不能访问的问题
|
11天前
|
网络协议 安全 API
Android网络和数据交互: 什么是HTTP和HTTPS?在Android中如何进行网络请求?
HTTP和HTTPS是网络数据传输协议,HTTP基于TCP/IP,简单快速,HTTPS则是加密的HTTP,确保数据安全。在Android中,过去常用HttpURLConnection和HttpClient,但HttpClient自Android 6.0起被移除。现在推荐使用支持TLS、流式上传下载、超时配置等特性的HttpsURLConnection进行网络请求。
10 0
|
20天前
|
应用服务中间件 网络安全 nginx
nginx配置https访问
nginx配置https访问
34 0
|
29天前
解决Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com
解决Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com
22 5
|
30天前
|
应用服务中间件 nginx
nginx配置https和直接访问静态文件的方式
nginx配置https和直接访问静态文件的方式
28 3