• HttpClient&&RestTemplate学习


    1. 什么是HttpClient

    HttpClient是Apache下面的子项目,可以提供高效的,最新的,功能丰富的支持HTTP协议的客户端编程工具包。



    2. 为什么要学习HttpClient

    • Http协议用的很多,很多程序需要直接通过HTTP协议来访问网络资源。当前大部分项目暴漏出来的接口是Http请求,数据格式是JSON格式。
    • 现在流行的SpringCloud服务与服务之间的调用底层就是通过HttpClient技术。
    • 可以实现多个系统之间的相互访问。



    3. HttpClient 提供的主要的功能

    (1)实现了所有 HTTP 的方法(GET,POST,PUT,DELETE 等)
    (2)支持自动转向
    (3)支持 HTTPS 协议
    (4)支持代理服务器等



    4. HttpClient的请求类型

    其实现了所有的Http请求类型,相应的类为
    HttpGet、HttpPost、HttpDelete、HttpPut



    5. HttpClient使用流程

    (1)创建HttpClient对象。
    (2)创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。
    (3)如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。
    (4)调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。
    (5)调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。
    (6)释放连接。无论执行方法是否成功,都必须释放连接。



    6. 发送一个Http请求访问百度试试

    转载
    大佬地址
    详细http的api
    api
    get请求:

    public static void main(String[] args) throws IOException {
            //1.打开浏览器
            CloseableHttpClient httpClient = HttpClients.createDefault();
            //2.声明get请求
            HttpGet httpGet = new HttpGet("http://www.baidu.com/");
            //3.发送请求
            CloseableHttpResponse response = httpClient.execute(httpGet);
            //4.判断状态码
            if(response.getStatusLine().getStatusCode()==200){
                HttpEntity entity = response.getEntity();
               //使用工具类EntityUtils,从响应中取出实体表示的内容并转换成字符串
                String string = EntityUtils.toString(entity, "utf-8");
                System.out.println(string);
            }
            //5.关闭资源
            response.close();
            httpClient.close();
    }
    

    post请求:

    public static void main(String[] args) throws IOException {
            //1.打开浏览器
            CloseableHttpClient httpClient = HttpClients.createDefault();
            //2.声明get请求
            HttpPost httpPost = new HttpPost("https://www.oschina.net/");
            //3.开源中国为了安全,防止恶意攻击,在post请求中都限制了浏览器才能访问
            httpPost.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36");
            //4.判断状态码
            List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
            parameters.add(new BasicNameValuePair("scope", "project"));
            parameters.add(new BasicNameValuePair("q", "java"));
    
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters,"UTF-8");
    
            httpPost.setEntity(formEntity);
    
            //5.发送请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
    
            if(response.getStatusLine().getStatusCode()==200){
                HttpEntity entity = response.getEntity();
                String string = EntityUtils.toString(entity, "utf-8");
                System.out.println(string);
            }
            //6.关闭资源
            response.close();
            httpClient.close();
        }
    

    6.1 创建HttpClient对象的几种方式

    HttpClient是一个接口,它的常用实现有AutoRetryHttpClient,CachingHttpClient,DecompressingHttpClient,其中CloseableHttpClient是它的抽象类。

    方式一:
          使用CloseableHttpClient的工厂类HttpClients的方法来创建实例。
          CloseableHttpClient httpClient = HttpClients.createDefault();
    
    方式二:
          使用CloseableHttpClient的builder类HttpClientBuilder,先对一些属性进行配置(采用装饰者模式,不断的.setxxxxx().setxxxxxxxx()就行了),再调用build方法来创建实例。
          CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    

    6.2 创建request请求

    提供的常用请求HttpGet、HttpPost、HttpDelete、HttpPut
    // 创建HttpGet请求,相当于在浏览器输入地址
    HttpGet httpGet = new HttpGet("http://www.baidu.com/");
    

    6.3 执行Request请求

    执行Request请求就是调用HttpClient的execute方法。
    CloseableHttpResponse response = httpClient.execute(httpGet);
    

    6.4 处理响应

    HttpClient发送请求后的响应其解析后的对象
    CloseableHttpClient发送请求后的响应则都是CloseableHttpResponse类型。[用的较多]。
    
    CloseableHttpResponse response = httpClient.execute(httpGet);
    //4.判断状态码
    if(response.getStatusLine().getStatusCode()==200){
          HttpEntity entity = response.getEntity();
          //使用工具类EntityUtils,从响应中取出实体表示的内容并转换成字符串
          String string = EntityUtils.toString(entity, "utf-8");
          System.out.println(string);
    }
    
    CloseableHttpResponse常用方法:
          自行百度吧
    
    关于其中有个方法         HttpEntity getEntity(); // 获取此响应的消息实体  
    
    HttpEntity常用方法:
          自行百度吧
    

    6.5 关闭HttpClient

    response.close();
    httpClient.close();
    


    7. 常见使用案例

    https://www.cnblogs.com/licl11092/p/9075677.html
    https://www.pianshen.com/article/401974721/
    https://blog.csdn.net/justry_deng/article/details/81042379
    https://blog.csdn.net/w372426096/article/details/82713315?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.not_use_machine_learn_pai
    https://www.cnblogs.com/kitor/p/11235762.html
    https://blog.csdn.net/wangpeng047/article/details/19624529
    https://blog.csdn.net/zhuwukai/article/details/78644484
    https://www.pianshen.com/article/401974721/



    8. 其他远程访问接口方式

    • java原生API       HttpURLConnection 在java.net包中,已经提供访问HTTP协议的基本功能类:HttpURLConnection,可以向其他系统发送GET,POST访问请求 转载
    • OKHttp                一种Client/Server模式,可以像调用本地方法一样去调用远程服务器上的方法,它支持多种协议(如:HTTP、TCP、UDP、自定协议)和多种数据传输方式
    • RestTemplate      由 Spring 提供的一个 HTTP 请求工具。
    • WebService        一种跨编程语言、跨操作系统平台的远程调用技术。 转载
    • WebSocket        一种在单个TCP连接上进行全双工通信的协议。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
    • ....欢迎评论补充



    9. RestTemplate

    参考大佬文章:https://blog.csdn.net/jinjiniao1/article/details/100849237
    RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,它提供了常见的REST请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及execute。
    总结来说就是:RestTemplate字面意思即支持Rest风格架构的互联网的请求方式模板它是一种支持REST风格并简化了发起http请求访问资源以及处理响应的方式。
    RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。
    相比使用Apache的HttpClient,RestTemplate提供了一种简单便捷的模板类来进行操作。我们只需要传入url及返回值类型即可。

    9.1 入门使用

    @RestController
    public class ServerController {
    	@GetMapping("/msg")
    	public String msg(){
    		return "this is product' msg";
    	}
    }
    
    public static void main(String[] args) {
    	//请求地址
    	String url = "http://localhost:8001/msg";
    	RestTemplate restTemplate = new RestTemplate();
    	String response = restTemplate.getForObject(url, String.class);
            log.info("response={}",response);
    }
    

    RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。
    其实,这里面只有11个独立的方法,其中有十个有三种重载形式,而第十一个则重载了六次,这样一共形成了36个方法。


    9.2 api解析

    a) 创建RestTemplate的三种方式

          RestTemplate restTemplate = new RestTemplate();
          RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
          RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    

    b) 常见的 GET,POST,PUT,DELETE 的用法

    //1. 简单Get请求
    String result = restTemplate.getForObject(rootUrl + "get1?para=my", String.class);
    System.out.println("简单Get请求:" + result);
    
    //2. 简单带路径变量参数Get请求
    result = restTemplate.getForObject(rootUrl + "get2/{1}", String.class, 239);
    System.out.println("简单带路径变量参数Get请求:" + result);
    
    //3. 返回对象Get请求(注意需包含compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5')
    ResponseEntity<Test1> responseEntity = restTemplate.getForEntity(rootUrl + "get3/339", Test1.class);
    System.out.println("返回:" + responseEntity);
    System.out.println("返回对象Get请求:" + responseEntity.getBody());
    
    //4. 设置header的Get请求
    HttpHeaders headers = new HttpHeaders();
    headers.add("token", "123");
    ResponseEntity<String> response = restTemplate.exchange(rootUrl + "get4", HttpMethod.GET, new HttpEntity<String>(headers), String.class);
    System.out.println("设置header的Get请求:" + response.getBody());
    
    //5. Post对象
    Test1 test1 = new Test1();
    test1.name = "buter";
    test1.sex = 1;
    result = restTemplate.postForObject(rootUrl + "post1", test1, String.class);
    System.out.println("Post对象:" + result);
    
    //6. 带header的Post数据请求
    response = restTemplate.postForEntity(rootUrl + "post2", new HttpEntity<Test1>(test1, headers), String.class);
    System.out.println("带header的Post数据请求:" + response.getBody());
    
    //7. 带header的Put数据请求
    //无返回值
    restTemplate.put(rootUrl + "put1", new HttpEntity<Test1>(test1, headers));
    //带返回值
    response = restTemplate.exchange(rootUrl + "put1", HttpMethod.PUT, new HttpEntity<Test1>(test1, headers), String.class);
    System.out.println("带header的Put数据请求:" + response.getBody());
    
    //8. del请求
    //无返回值
    restTemplate.delete(rootUrl + "del1/{1}", 332);
    //带返回值
    response = restTemplate.exchange(rootUrl + "del1/332", HttpMethod.DELETE, null, String.class);
    System.out.println("del数据请求:" + response.getBody());
    

    c) Get请求解析
    看完上面这么多示例,我们来详解一下Get请求。

    getForEntity
    既然 RestTemplate 发送的是 HTTP 请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用 getForEntity 来发送 HTTP 请求,此时返回的对象是一个 ResponseEntity 的实例。这个实例中包含了响应数据以及响应头。

    ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, name);
    

    getForEntity 方法。第一个参数是 url ,url 中有一个占位符 {1} ,如果有多个占位符分别用 {2} 、 {3} … 去表示,第二个参数是接口返回的数据类型,最后是一个可变长度的参数,用来给占位符填值。在返回的 ResponseEntity 中,可以获取响应头中的信息,其中 getStatusCode 方法用来获取响应状态码, getBody 方法用来获取响应数据, getHeaders 方法用来获取响应头。

    getForObject
    getForObject 方法和 getForEntity 方法类似。
    getForObject 和 getForEntity 的差异,这两个的差异主要体现在返回值的差异上, getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。

    String s = restTemplate.getForObject(uri, String.class);
    

    c) Post请求解析
    和 GET 请求相比,RestTemplate 中的 POST 请求多了一个类型的方法。

    postForEntity
    根据上述描述,可以发现postForEntity可以传递参数为key/value的map形式,json,还能像gey请求那样的传递 key/value 形式的参数。

    String url = "http://" + host + ":" + port + "/hello2";
    ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, map, String.class);
    
    String url = "http://" + host + ":" + port + "/hello2?name={1}";
    ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, null, String.class,name);
    

    postForEntity之传递 JSON 数据
    上面已经说了postForEntity可以传递JSON参数。在 post 请求中,可以自动将一个对象转换成 json 进行传输,数据到达目标接口之后,再被转换为一个对象。

    public class User {
        private String username;
        private String address;
        //省略getter/setter
    }
    
    @Controller
    @ResponseBody
    public class UserController {
        @PostMapping("/user")
        public User hello(@RequestBody User user) {
            return user;
        }
    }
    
    @GetMapping("/hello7")
    public User hello7() {
        List<ServiceInstance> list = discoveryClient.getInstances("provider");
        ServiceInstance instance = list.get(0);
        String host = instance.getHost();
        int port = instance.getPort();
        String url = "http://" + host + ":" + port + "/user";
        User u1 = new User();
        u1.setUsername("牧码小子");
        u1.setAddress("深圳");
        ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, u1, User.class);
        return responseEntity.getBody();
    }
    

    postForObject
    postForObject 和 postForEntity 基本一致,就是返回类型不同而已,这里不再赘述。

    postForLocation
    postForLocation 方法的返回值是一个 Uri 对象,因为 POST 请求一般用来添加数据,有的时候需要将刚刚添加成功的数据的 URL 返回来,此时就可以使用这个方法,一个常见的使用场景如用户注册功能,用户注册成功之后,可能就自动跳转到登录页面了,此时就可以使用该方法。
    例如在 provider 中提供一个用户注册接口,再提供一个用户登录接口,如下:

    @RequestMapping("/register")
    public String register(User user) throws UnsupportedEncodingException {
        return "redirect:/loginPage?username=" + URLEncoder.encode(user.getUsername(),"UTF-8") + "&address=" + URLEncoder.encode(user.getAddress(),"UTF-8");
    }
    @GetMapping("/loginPage")
    @ResponseBody
    public String loginPage(User user) {
        return "loginPage:" + user.getUsername() + ":" + user.getAddress();
    }
    

    这里一个注册接口,一个是登录页面,不过这里的登录页面我就简单用一个字符串代替了。然后在 consumer 中来调用注册接口,如下:

    @GetMapping("/hello8")
    public String hello8() {
        List<ServiceInstance> list = discoveryClient.getInstances("provider");
        ServiceInstance instance = list.get(0);
        String host = instance.getHost();
        int port = instance.getPort();
        String url = "http://" + host + ":" + port + "/register";
        MultiValueMap map = new LinkedMultiValueMap();
        map.add("username", "牧码小子");
        map.add("address", "深圳");
        URI uri = restTemplate.postForLocation(url, map);
        String s = restTemplate.getForObject(uri, String.class);
        return s;
    }
    

    这里首先调用 postForLocation 获取 Uri 地址,然后再利用 getForObject 请求 Uri,结果如下:
    参考大佬文章:https://blog.csdn.net/jinjiniao1/article/details/100849237

    注意:postForLocation 方法返回的 Uri 实际上是指响应头的 Location 字段,所以,provider 中 register 接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则 postForLocation 方法的返回值为null,初学者很容易犯这个错误,如果这里出错,大家可以参考下我的源代码。

  • 相关阅读:
    截取url中最后斜杆的文件名
    html span从上往下,从左往右排序
    浪漫源码记录
    微信小程序TypeError: Cannot read property 'elem' of undefined
    tomcat8 性能优化
    Bandicam神奇使用法
    DataStage 七、在DS中使用配置文件分配资源
    DataStage 六、安装和部署集群环境
    DataStage 错误集(持续更新)
    DataStage 三、配置ODBC
  • 原文地址:https://www.cnblogs.com/itlihao/p/14316921.html
Copyright © 2020-2023  润新知