【仓颉三方库】 网络组件——httpclient4cj

39 篇文章 0 订阅
39 篇文章 0 订阅

软件架构

架构图

源码目录

.
├── README.md
├── doc
│   ├── assets
│   ├── cjcov     
│   ├── feature_api.md  
│   └── design.md
└── src

  • doc是库的设计文档、提案、库的使用文档、LLT 覆盖报告 ( 由于未支持服务端的对接,部分拦截器连接后处理逻辑暂时无法覆盖)
  • src是库源码目录

接口说明

主要是核心类和成员函数说明,详情见 API

编译执行

编译

编译描述和具体shell命令

  1. linux x86_64 编译

执行下面执行

    ./build_linux.sh
  1. windows x64 编译

执行下面执行

    build_windows.bat
  1. ohos编译

执行下面执行

    ./build_ohos.sh

示例

注意:以下示例请将url地址换成实际可用地址。

获取HttpClient对象并配置超时时间

import httpclient4cj
import httpclient4cj.*
import std.time.*

main() {
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
}

同步 GET 请求方法示例

import httpclient4cj
import httpclient4cj.*
import std.time.*
import encoding.url.*

main() {
    let url = URL.parse("http://127.0.0.1:50060")
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder().url(url).build()
    let call = client.newCall(request)
    let response = call.execute()
    println(response.getBody().getOrThrow().getString())
}

同步 Post 发送json字符串

import httpclient4cj
import httpclient4cj.*
import std.time.*

main() {
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder()
        .url("http://127.0.0.1:50060")
        .post(RealRequestBody.create(MediaType.get("application/json; charset=utf-8"), "{\"id\": \"123\"}"))
        .build()
    let response = client.newCall(request).execute()
    println(response.getBody().getOrThrow().getString())
}

同步 Post 发送文件内容

import httpclient4cj
import httpclient4cj.*
import std.time.*
import std.fs.*

main() {
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    var arr: Array<Byte> = Array<Byte>(1024, {i => UInt8(i % 256)})
    File.writeTo("./body.txt", arr)
    let file = File("./body.txt", OpenOption.Open(true, false))
    let body = RealRequestBody.create(MediaType.get("text/plain"), file)
    let request: httpclient4cj.Request = httpclient4cj.Request.builder()
        .url("http://127.0.0.1:50060")
        .post(body)
        .build()
    let response: httpclient4cj.Response = client.newCall(request).execute()
    println(response.getBody().getOrThrow().getString())
    File.delete("./body.txt")
}

multipart 发送数据以及多上传文件

import httpclient4cj
import httpclient4cj.*
import std.time.*
import std.fs.*

main() {
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    var arr: Array<Byte> = Array<Byte>(1024, {i => UInt8(i % 256)})
    File.writeTo("./body1.txt", arr)
    File.writeTo("./body2.txt", arr)
    let body1 = RealRequestBody.create(MediaType.get("text/plain"), File("./body1.txt", OpenOption.Open(true, false)))
    let body2 = RealRequestBody.create(MediaType.get("text/plain"), File("./body2.txt", OpenOption.Open(true, false)))
    let mu = MultipartBody.builder()
        .addFormDataPart("name", "huluwa")
        .addFormDataPart("age", "18")
        .addFormDataPart("file1", "body1.txt", body1)
        .addFormDataPart("file2", "body2.txt", body2)
        .build()
    let request = Request.builder().url("http://127.0.0.1:50060").post(mu).build()
    let response: httpclient4cj.Response = client.newCall(request).execute()
    println(response.getBody().getOrThrow().getString())
    File.delete("./body1.txt")
    File.delete("./body2.txt")
}

chunked分块传输请求

import httpclient4cj
import httpclient4cj.*
import std.time.*
import std.io.*

main() {
    let client: HttpClient = HttpClient.builder().build()
    let request = httpclient4cj.Request.builder().url("http://127.0.0.1:50060").post(MyRequestBody()).build()
    let response = client.newCall(request).execute()
    println(response.getBody().getOrThrow().getString())
}
class MyRequestBody <: RequestBody {
    public func contentType(): Option<MediaType> {
        return MediaType.parse("application/json")
    }
    public func getContentLength(): Int64 {
        // 声明的getContentLength -1,客户端拦截器默认添加"Transfer-Encoding", "chunked"头,使用ChunkedSink读取body
        return -1
    }
    public func writeTo(sink: Sink): Unit {
        // 每次调用write都会产生一个传输块
        sink.write("hello".toArray())
        sink.write("world".toArray())
    }
    public func get(): InputStream {
        return ByteArrayStream()
    }
}

异步请求以及回调

import httpclient4cj
import httpclient4cj.*
import std.time.*

main() {
    let client: HttpClient = HttpClient.builder()
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder()
        .url("http://127.0.0.1:50060")
        .header("User-Agent", "Httpclient4cj-Example")
        .build()
    for (i in 0..5) {
        let async = client.newCall(request)
        async.enqueue(MyCallbacks())
    }
    sleep(Duration.second)
}
public class MyCallbacks <: Callback {
    public func onFailure(call: Call, e: Exception): Unit {
        println("fail, ${e.message}")
    }
    public func onResponse(call: Call, response: Response): Unit {
        println(response)
    }
}

拦截器使用

import httpclient4cj
import httpclient4cj.*
import std.time.*

main() {
    let client: HttpClient = HttpClient.builder()
        .addNetworkInterceptor(MyInterceptor())
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder().url("http://127.0.0.1:50060").build()
    let response: Response = client.newCall(request).execute()
    println(response.getBody().getOrThrow().getString())
    return 0
}
// 自定义拦截器打印route地址
class MyInterceptor <: Interceptor {
    public func intercept(chain: Chain): httpclient4cj.Response {
        let conn = chain.getConnection().getOrThrow()
        println("route = ${conn.getRoute().getInetSocketAddress()}")
        return chain.proceed(chain.getRequest())
    }
}

cookie管理

import encoding.url.*
import httpclient4cj
import httpclient4cj.*
import std.time.*

main() {
    let url: URL = URL.parse("http://127.0.0.1:50060")
    let jar = getSimpleCookieJar()
    let client: HttpClient = HttpClient.builder()
        .cookieJar(jar)
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = httpclient4cj.Request.builder().url(url).build()
    let call = client.newCall(request)
    let response: httpclient4cj.Response = call.execute()
    for (cookie in client.getCookieJar().loadForRequest(url)) {
        println(cookie.toSetCookieString())
    }
    return 0
}

监听器使用

import encoding.url.*
import httpclient4cj
import httpclient4cj.*
import net.tls.*
import std.collection.*
import std.socket.*
import std.time.*

main() {
    let url = URL.parse("http://127.0.0.1:50060")
    let client: HttpClient = HttpClient.builder()
        .eventListener(MyEventListener())
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder().url(url).build()
    let call = client.newCall(request)
    let response = call.execute()
    println(response.getBody().getOrThrow().getString())
    return 0
}
class MyEventListener <: EventListener {
    public func callStart(call: Call): Unit {
        println("callStart!!!")
    }
    public func callEnd(call: Call): Unit {
        println("callEnd!!!")
    }
    public func dnsStart(call: Call, domainName: String): Unit {
        println("dnsStart!!!")
    }
    public func dnsEnd(call: Call, domainName: String, allRoutes: ArrayList<Route>): Unit {
        println("dnsEnd!!!")
    }
    public func connectStart(call: Call, socketAddress: SocketAddress): Unit {
        println("connectStart!!!")
    }
    public func connectEnd(call: Call, socketAddress: SocketAddress, protocol: Protocol): Unit {
        println("connectEnd!!!")
    }
    public func secureConnectStart(call: Call): Unit {
        println("secureConnectStart!!!")
    }
    public func secureConnectEnd(call: Call, tlsConfig: TlsClientConfig): Unit {
        println("secureConnectEnd!!!")
    }
    public func connectFailed(call: Call, socketAddress: SocketAddress, protocol: Protocol, e: HttpException): Unit {
        println("connectFailed!!!")
    }
    public func requestHeadersStart(call: Call): Unit {
        println("requestHeadersStart!!!")
    }
    public func requestHeadersEnd(call: Call): Unit {
        println("requestHeadersEnd!!!")
    }
    public func requestBodyStart(call: Call): Unit {
        println("requestBodyStart!!!")
    }
    public func requestBodyEnd(call: Call, byteCount: Int64): Unit {
        println("requestBodyEnd!!!")
    }
    public func requestFailed(call: Call, e: HttpException): Unit {
        println("requestFailed!!!")
    }
    public func responseHeadersStart(call: Call): Unit {
        println("responseHeadersStart!!!")
    }
    public func responseHeadersEnd(call: Call, response: Response): Unit {
        println("responseHeadersEnd!!!")
    }
    public func responseBodyStart(call: Call): Unit {
        println("responseBodyStart!!!")
    }
    public func responseBodyEnd(call: Call, byteCount: Int64): Unit {
        println("responseBodyEnd!!!")
    }
    public func responseFailed(call: Call, e: HttpException): Unit {
        println("responseFailed!!!")
    }
}

使用http2协议

import encoding.url.*
import httpclient4cj
import httpclient4cj.*
import net.tls.*
import std.collection.*
import std.time.*

main() {
    let url = URL.parse("http://127.0.0.1:50060")
    // 需要用户自己配置CA证书验证公钥,如果不配置CA证书将不进行服务端证书校验,将使用不安全的连接
    // H2_PRIOR_KNOWLEDGE 使用明文http2协议, 不支持https
    // .protocols(ArrayList<String>([Protocol.get("H2_PRIOR_KNOWLEDGE").toString()]))
    // 使用apln协商协议,服务端响应支持的协议,list中前面的协议会被优先选择
    let client: HttpClient = HttpClient.builder()
        .tlsConfig(TlsClientConfig())
        .protocols(ArrayList<String>([Protocol.get("HTTP/2.0").toString(), Protocol.get("HTTP/1.1").toString()]))
        .connectTimeout(Duration.second)
        .readTimeout(Duration.second)
        .writeTimeout(Duration.second)
        .build()
    let request = Request.builder().url(url).build()
    let call = client.newCall(request)
    let response = call.execute()
    println(response)
    return 0
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值