0


【2023】java常用HTTP客户端对比以及使用(HttpClient/OkHttp/WebClient)

💻目录

1、介绍

现在java使用的http客户端主要包括以下几种
java使用http通讯
而这些中使用得最频繁的主要是:

  1. Apache HttpClient:这是一个功能强大且广泛使用的第三方库,用于进行HTTP通讯。它提供了更高级的API和更丰富的功能,比如支持连接池、认证、重定向、Cookie管理等。Apache HttpClient可以作为独立的库使用,也可以作为Apache HttpComponents项目的一部分。
  2. OkHttp:这是另一个流行的第三方库,用于进行HTTP通讯。OkHttp提供了简洁的API和高性能的特性,支持同步和异步请求,以及连接池、缓存、拦截器等功能。OkHttp也是Square公司的一个开源项目。
  3. Spring WebClient:这是Spring框架中的一个模块,是RestTemplate的升级版,用于进行非阻塞的HTTP通讯。它基于Reactive Streams编程模型,适用于构建响应式的应用程序。Spring WebClient提供了简单的API来发送HTTP请求和处理响应,可以与Spring WebFlux等模块一起使用。

2、使用

下面展示了Apache HttpClient和OkHttp以及Spring WebClient的常用使用方式,包括get和post

2.1、添加配置

2.1.1、依赖

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 --><dependency><groupId>org.apache.httpcomponents.client5</groupId><artifactId>httpclient5</artifactId></dependency><!--okhttp--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency><!--webClient--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>

2.1.2、工具类

  • Result:统一返回类
@DatapublicclassResult<T>{//状态码privateInteger code;//信息privateString message;//数据privateT data;privateResult(){}//设置数据,返回对象的方法publicstatic<T>Result<T>build(T data,ResultCodeEnum resultCodeEnum){//创建Result对象,设置值,返回对象Result<T> result =newResult<>();//判断返回结果中是否需要数据if(data !=null){//设置数据到result对象
            result.setData(data);}//设置其他值
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());//返回设置值之后的对象return result;}//成功的方法publicstatic<T>Result<T>ok(T data){returnbuild(data,ResultCodeEnum.SUCCESS);}//成功的方法publicstatic<T>Result<T>ok(){returnbuild(null,ResultCodeEnum.SUCCESS);}//失败的方法publicstatic<T>Result<T>fail(T data){returnbuild(data,ResultCodeEnum.FAIL);}}
  • ResultCodeEnum:返回结果
@GetterpublicenumResultCodeEnum{SUCCESS(200,"成功"),FAIL(201,"失败"),;privateInteger code;privateString message;ResultCodeEnum(Integer code,String message){this.code = code;this.message = message;}}

2.1.3、实体

  • User
@DatapublicclassUser{privateString name;privateInteger age;privateInteger post;}
  • ProductInfo:返回数据
@Data@AllArgsConstructor@NoArgsConstructor@ToStringpublicclassProductInfoimplementsSerializable{privateLong id;/**销量*/privateInteger sale;/**价格*/privateInteger price;/**名称*/privateString name;/**类型*/privateInteger type;/**端口*/privateInteger port;}

2.1.4、Controller接口

@RestController@RequestMapping("/productInfo/index")publicclassProductInfoController{@ResourceprivateProductInfoService productInfoService;//    获取当前服务的端口@Value("${server.port}")privateInteger port;@GetMapping("/get")publicResult<?>get(Integer type){List<ProductInfo> productInfoList =getProductInfoList(type);System.out.println(productInfoList);returnResult.ok(productInfoList);}@PostMapping("/post")publicResult<?>post(@RequestBodyUser user){Integer post = user.getPost();List<ProductInfo> productInfoList =getProductInfoList(post);System.out.println(productInfoList);returnResult.ok(productInfoList);}publicList<ProductInfo>getProductInfoList(Integer type){ProductInfo productInfo3 =newProductInfo(3l,800,20,"哈密瓜1",1,port);ProductInfo productInfo1 =newProductInfo(1l,50,8,"苹果1",1,port);ProductInfo productInfo2 =newProductInfo(2l,200,13,"牛肉1",2,port);ProductInfo productInfo4 =newProductInfo(4l,50,9,"青菜1",2,port);/*        实际项目中,会从数据库查出数据 */List<ProductInfo> productInfoList =Arrays.asList(productInfo1,productInfo2,productInfo3,productInfo4);//        根据传入的类型返回指定类型List<ProductInfo> result = productInfoList.stream().filter(productInfo -> productInfo.getType()== type).collect(Collectors.toList());return result;}}

2.2、Apache HttpClient使用

  • get使用 默认只能同步异步需要加额外的依赖,get请求不能携带参数,只能通过拼接路径
<!--异步请求--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpasyncclient</artifactId></dependency>
publicstaticvoidget(CloseableHttpClient httpClient,String url){//            连接对象try{//        HttpGet不能携带参数,如果需要参数只能通过拼接HttpGet httpGet =newHttpGet(url+"?type=1");String execute = httpClient.execute(httpGet, response ->{JSONObject entries =newJSONObject(EntityUtils.toString(response.getEntity()));Result result =JSONUtil.toBean(entries,Result.class);if(result.getCode()==200){String data = result.getData().toString();System.out.println(data);return data;}else{System.err.println(result.getMessage());return result.getMessage();}});System.out.println("get成功结果:"+execute);}catch(Exception e){
            e.printStackTrace();}}
  • post post请求,通过setEntity()给HttpPost对象添加请求对象
publicstaticvoidpost(CloseableHttpClient httpClient,String url){HttpPost httpPost =newHttpPost(url);User user =newUser();
        user.setPost(1);//        添加参数对象
        httpPost.setEntity(newStringEntity(JSONUtil.toJsonStr(user)));// 设置请求头
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE,"application/json");try{String execute = httpClient.execute(httpPost, response ->{JSONObject entries =newJSONObject(EntityUtils.toString(response.getEntity()));Result result =JSONUtil.toBean(entries,Result.class);if(result.getCode()==200){String data = result.getData().toString();
                    log.info(data);return data;}else{
                    log.error(result.getMessage());return result.getMessage();}});
            log.info("HttpClient的post成功结果:"+execute);}catch(IOException e){
            e.printStackTrace();}}
  • 全部代码

执行步骤

  1. 创建CloseableHttpClient对象
  2. 创建get获取post请求对象
  3. 通过execute()方法发送请求
  4. 通过response.getEntity()获取响应回来的数据
@Slf4jpublicclassHttpClientUtil{privatestaticString postUrl ="http://localhost:8202/productInfo/index/post";privatestaticString getUrl ="http://localhost:8202/productInfo/index/get";publicstaticvoidmain(String[] args){try{//            创建客户端对象CloseableHttpClient client =HttpClients.createDefault();get(client,getUrl);post(client,postUrl);
            client.close();}catch(IOException e){
            e.printStackTrace();}}publicstaticvoidget(CloseableHttpClient httpClient,String url){//            连接对象try{//        HttpGet不能携带参数,如果需要参数只能通过拼接HttpGet httpGet =newHttpGet(url+"?type=1");String execute = httpClient.execute(httpGet, response ->{JSONObject entries =newJSONObject(EntityUtils.toString(response.getEntity()));Result result =JSONUtil.toBean(entries,Result.class);if(result.getCode()==200){String data = result.getData().toString();
                    log.info(data);return data;}else{
                    log.info(result.getMessage());return result.getMessage();}});
            log.info("HttpClient的get成功结果:"+execute);}catch(Exception e){
            e.printStackTrace();}}publicstaticvoidpost(CloseableHttpClient httpClient,String url){HttpPost httpPost =newHttpPost(url);User user =newUser();
        user.setPost(1);//        添加参数对象
        httpPost.setEntity(newStringEntity(JSONUtil.toJsonStr(user)));// 设置请求头
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE,"application/json");try{String execute = httpClient.execute(httpPost, response ->{JSONObject entries =newJSONObject(EntityUtils.toString(response.getEntity()));Result result =JSONUtil.toBean(entries,Result.class);if(result.getCode()==200){String data = result.getData().toString();
                    log.info(data);return data;}else{
                    log.error(result.getMessage());return result.getMessage();}});
            log.info("HttpClient的post成功结果:"+execute);}catch(IOException e){
            e.printStackTrace();}}}

2.3 、OkHttp使用

执行步骤

  1. 创建OkHttpClient对象,用于配置和管理HTTP请求的行为
  2. 创建Request对象,用于描述要发送的HTTP请求。Request对象包含了URL、请求方法、请求头、请求体等信息。
  3. 创建Call对象,使用OkHttpClient的newCall()方法,传入Request对象,创建一个Call对象,Call对象表示一次HTTP请求的调用,可以用于执行同步或异步的请求。
  4. 执行请求,同步通过Call对象的execute()方法来;异步通过Call对象的enqueue()方法来执行请求,并通过回调函数处理响应
  5. 解析响应,通过response.body()得到响应的内容在通过json解析。
@Slf4jpublicclassOkHttpUtil{privatestaticString postUrl ="http://localhost:8202/productInfo/index/post";privatestaticString getUrl ="http://localhost:8202/productInfo/index/get";publicstaticvoidmain(String[] args){OkHttpClient client =newOkHttpClient().newBuilder().connectTimeout(30,TimeUnit.SECONDS)//连接超时时间.writeTimeout(30,TimeUnit.SECONDS)//请求超时时间.readTimeout(30,TimeUnit.SECONDS)//响应超时时间.build();//        get(client);//        asyncGet(client);//        post(client);asyncPost(client);}/**
     * 同步get
     * @param client        
     * @return void
     */publicstaticvoidget(OkHttpClient client){//        创建get请求对象Request request =newRequest.Builder().url(getUrl+"?type=1").get().header("Content-Type","application/json")// 设置Content-Type请求头.build();try{//            返回响应对象Response response = client.newCall(request).execute();//              验证响应是否成功if(!response.isSuccessful())thrownewIOException("Unexpected code "+ response);//              解码对象Result result =JSONUtil.toBean(response.body().string(),Result.class);Object data = result.getData();System.out.println(data);}catch(IOException e){
            e.printStackTrace();}}/**
     * 异步get
     * @param client
     * @return void
     */publicstaticvoidasyncGet(OkHttpClient client){//        创建get请求对象Request request =newRequest.Builder().url(getUrl+"?type=1").get()//不指定请求方式默认是get.build();//           异步发送请求,没有返回结果
        client.newCall(request).enqueue(newCallback(){//               处理失败请求@OverridepublicvoidonFailure(Call call,IOException e){
                log.debug("Unexpected code "+ e.getMessage());
                e.printStackTrace();}//            处理成功请求@OverridepublicvoidonResponse(Call call,Response response)throwsIOException{//              验证响应是否成功if(!response.isSuccessful())thrownewIOException("Unexpected code "+ response);//              解码对象Result result =JSONUtil.toBean(response.body().string(),Result.class);Object data = result.getData();System.out.println(data);}});}/**
     * 同步post
     * @param client
     * @return void
     */publicstaticvoidpost(OkHttpClient client){User user =newUser();
        user.setPost(1);String str =JSONUtil.toJsonStr(user);Request request =newRequest.Builder().url(postUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), str)).build();Call call = client.newCall(request);try{Response response = call.execute();//              验证响应是否成功if(!response.isSuccessful())thrownewIOException("Unexpected code "+ response);//              解码对象Result result =JSONUtil.toBean(response.body().string(),Result.class);Object data = result.getData();
            log.info("post请求成功,返回结果:{}",data);}catch(IOException e){
            e.printStackTrace();}}/**
     * 异步post请求
     * @param client        
     * @return void
     */publicstaticvoidasyncPost(OkHttpClient client){User user =newUser();
        user.setPost(1);//          把对象转为json字符串String str =JSONUtil.toJsonStr(user);Request request =newRequest.Builder().url(postUrl).post(RequestBody.create(MediaType.parse(ContentType.JSON.getValue()), str)).build();Call call = client.newCall(request);//       异步请求没返回
        call.enqueue(newCallback(){//            请求异常@OverridepublicvoidonFailure(Call call,IOException e){
                log.debug("Unexpected code "+ e.getMessage());
                e.printStackTrace();}//            请求成功@OverridepublicvoidonResponse(Call call,Response response)throwsIOException{//              验证响应是否成功if(!response.isSuccessful())thrownewIOException("Unexpected code "+ response);//              解码对象Result result =JSONUtil.toBean(response.body().string(),Result.class);Object data = result.getData();
                log.info("异步post请求成功,返回结果:{}",data);}});}}

2.4、WebClient使用

执行步骤:

  1. 创建WebClient对象,推荐使用WebClient.builder()的方式创建,因为可以自定义配置客户端的参数,直接new是只能使用默认的配置。
  2. 构建请求,直接通过webClient对象,如get()、post()等,构建一个请求(如果没有指定请求方式),默认是get请求。
  3. 处理响应:使用响应对象(如Mono、Flux等)来处理响应数据。你可以通过操作符(如map()、flatMap()等)对响应进行转换、过滤、合并等操作。
  4. 订阅响应:使用subscribe()方法来订阅响应流,启动请求并处理响应数据。你可以通过回调函数或操作符链来处理响应数据。
@Component@Slf4jpublicclassWebClientUtil{privatestaticString postUrl ="http://localhost:8202/productInfo/index/post";privatestaticString getUrl ="http://localhost:8202/productInfo/index/get";/**
     * 同步执行get请求
     * @param webClient
     * @return void
     */publicvoidget(WebClient webClient){Mono<Result> mono = webClient.get().uri(getUrl +"?type=2").retrieve().bodyToMono(Result.class);//        获取返回结果 block()会进行堵塞,等待返回结果Result result = mono.block();if(result.getCode()==200){
            log.info("get请求返回结果{}",result.getData());}}/**
     * 异步get
     * @return void
     */publicvoidasyncGet(){HttpClient client =HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS,10000)//设置连接超时.doOnConnected(conn -> conn
                        .addHandler(newReadTimeoutHandler(10,TimeUnit.SECONDS))//写入超时.addHandler(newWriteTimeoutHandler(10)));//读取超时//        也可以以这种方式创建WebClient可以添加请求头和url以及一些参数;WebClient webClient =WebClient.builder().clientConnector(newReactorClientHttpConnector(client)).baseUrl(getUrl).defaultHeader(HttpHeaders.USER_AGENT,"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)")//                .defaultCookie()  //添加请求Cookie.build();//        获取返回结果Mono<Result> mono = webClient.get().uri("?type=2")// 请求路径,会拼接上面的.accept(MediaType.APPLICATION_JSON)//                .retrieve() //获取响应体//                .bodyToMono(Result.class);  //指定获取的类型,直接获取结果。//                或者通过该方式手动处理结果.exchangeToMono(response->{if(response.statusCode().equals(HttpStatus.OK)){//                        成功返回return response.bodyToMono(Result.class);}else{//                        失败返回return response.createException().flatMap(Mono::error);}});//        异步获取返回结果
        mono
                .subscribe(result ->{if(result.getCode()==200){
                        log.info("get请求返回结果{}", result.getData());}});System.out.println("执行完成");}/**
     * 同步post
     * @return void
     */publicvoidpost(){// 创建 WebClient 对象WebClient webClient =WebClient.builder().baseUrl(getUrl).build();User user =newUser();
        user.setPost(2);Mono<Result> mono = webClient
                .post().uri(postUrl).contentType(MediaType.APPLICATION_JSON).header("token","12321412").body(BodyInserters.fromValue(user)).retrieve().bodyToMono(Result.class);Result result = mono.block();if(result.getCode()==200){
            log.info("post请求返回结果{}",result.getData());}}/**
     * WebClient异步请求
     * @return void
     */publicvoidasyncPost(){// 创建 WebClient 对象WebClient webClient =WebClient.builder().baseUrl(getUrl).build();User user =newUser();
        user.setPost(2);Mono<Result> mono = webClient
                .post().uri(postUrl).contentType(MediaType.APPLICATION_JSON)//指定类型.header("token","12321412")//添加请求头.body(BodyInserters.fromValue(user))//添加请求对象.retrieve().bodyToMono(Result.class);//          异步请求
        mono.subscribe(result ->{if(result.getCode()==200){
                log.info("post异步请求返回结果{}",result.getData());}});}}
标签: java http okhttp

本文转载自: https://blog.csdn.net/weixin_52315708/article/details/135464246
版权归原作者 方渐鸿 所有, 如有侵权,请联系我们删除。

“【2023】java常用HTTP客户端对比以及使用(HttpClient/OkHttp/WebClient)”的评论:

还没有评论