使用httpclient 遇到的一个问题?

使用httpclient 遇到的一个问题

服务端请求的url

HttpPost post = new HttpPost("http://localhost:9091/receive/"+receiverIdParam);

客户端的接口

 @PostMapping("/receive/{id}")
    public Result receive(HttpServletRequest request,
                                  @RequestParam("file") MultipartFile file,
                                  @PathVariable("receiverIdParam") String receiverIdParam){

目前出现这个问题
@Pathvariable Required URI template variable 'receiverIdParam' for method parameter type String is not present]

@PostMapping("/receive/{id}")中{}里面的变量名,与@PathVariable("receiverIdParam")中的名称要一致。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以看下这个问题的回答https://ask.csdn.net/questions/737184
  • 这篇博客也不错, 你可以看下如何在.Net中利用HttpClient发送HTTP请求
  • 除此之外, 这篇博客: HttpClient发送请求中的 具体实现: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:
    1. 基于springboot项目,添加httpclient依赖;

      <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
      </dependency>
      
    2. GET请求

      不管怎么说,步骤里肯定有创建HttpClient对象,HttpGet对象,Params请求参数(有参的情况下);尤其是Params的添加,因为大家需求不同,需要传的参数以及类型不同,对于参数的封装方式就有不同;

      public static String sendGetForm(String url, Map<String, String> params) {
             try (CloseableHttpClient httpClient = HttpClients.createDefault()){
                 String param = "";
                 if (params != null) {
                     Set<Entry<String, String>> set = params.entrySet();
                     for(Entry<String, String> entry : set) {
                        if(param.isEmpty()) {
                           param = entry.getKey() + "=" + entry.getValue();
                        }else {
                           param = param + "&" + entry.getKey() + "=" + entry.getValue();
                        }
                     }
                 }
                 url = param.isEmpty() ? url : url + "?" + param;
                 HttpGet httpGet = new HttpGet(url);
                 try(CloseableHttpResponse response = httpClient.execute(httpGet)){
                      return EntityUtils.toString(response.getEntity(), "utf-8");
                 }
             } catch (Exception e) {
                 log.error("发送get请求失败", e);
            throw new RuntimeException("发送get请求失败", e);
             }
      }
      

      简单介绍一下吧:

      • 创建httpClient,至于为什么声明的CloseableHttpClient 类,这个类可以在我们请求完自动释放连接;

        CloseableHttpClient httpClient = HttpClients.createDefault()

      • 下面定义param参数配置到url后

        这样请求参数可有可无,并且参数放到url后需要的格式;

      • 创建httpGet请求对象

        HttpGet httpGet = new HttpGet(url);

      • 发送请求,接收响应(配置响应体)

        CloseableHttpResponse response = httpClient.execute(httpGet)

    3. POST请求

      POST请求又不一样啦,因为它有请求体可以传各种类型的数据(content-type)

      看了一下公司封装好的post请求,真的好多种,根据你要传的参数不同,需要配置的请求头、请求体就有所不同;所以在我们使用发送方法前要提前明白自己需要传什么样的数据,这样也就知道需要如何封装请求参数;、

      对于返回的请求结果response后面的,一般就是将获取到的响应体进行一个编码,防止中文乱码等;

      //Post方式表单提交
      public static String sendPostForm(String url, Map<String, String> params) {
             try (CloseableHttpClient httpClient = HttpClients.createDefault()){
                 HttpPost httpPost = new HttpPost(url);
                 if (params != null) {
                     List<NameValuePair> nameValuePairs = new ArrayList<>();
                     for (String key : params.keySet()) {
                         nameValuePairs.add(new BasicNameValuePair(key, params.get(key)));
                     }
                     UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs);
                     httpPost.setEntity(entity);
                 }
                 try(CloseableHttpResponse response = httpClient.execute(httpPost)){
                      return EntityUtils.toString(response.getEntity(), "utf-8");
                 }
             } catch (Exception e) {
                 log.error("发送post请求失败", e);
            throw new RuntimeException("发送post请求失败", e);
             }
      }
      
      //发送json格式数据
      public static String sendPostJson(String url, String json) {
             try (CloseableHttpClient httpClient = HttpClients.createDefault()){
                 HttpPost httpPost = new HttpPost(url);
                 StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
                 httpPost.setEntity(entity);
                 try(CloseableHttpResponse response = httpClient.execute(httpPost)){
                      return EntityUtils.toString(response.getEntity(), "utf-8");
                 }
             } catch (Exception e) {
                 log.error("发送post请求失败", e);
            throw new RuntimeException("发送post请求失败", e);
             }
      }
      

      艰难介绍一下:

      • 介于NameValuePair类型,叫做简单名称值对节点类型,就是请求数据中要求的参数类型吧;
      • 介于UrlEncodedFormEntity(URL实体转换工具)而且它直接在请求数据上指定了content-type的值;也可以用httpPost.addHeader(“contetntType”,“xxx”)来指定请求数据类型;
      • 发送json格式数据和表单数据,对应的请求content-type 也就不同。

      还有一个就是通过post请求发送文件

      private String sendFile( String url,MultipartFile file,HashMap<String,String> map) throws IOException {
              CloseableHttpClient httpclient = HttpClients.createDefault();
              HttpPost httpPost = new HttpPost(url);
              String rspMsg =null;
        
              MultipartEntityBuilder params = MultipartEntityBuilder.create();
        		//定义post请求的请求数据类型
              ContentType strContent = ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(),Consts.UTF_8);
        		//将文件放到请求体中
              params.addBinaryBody("file", file.getInputStream(), ContentType.DEFAULT_BINARY, file.getOriginalFilename());
        		//添加需要发送的普通参数
              params.addTextBody("waterno",map.get("waterno"),strContent);
              params.addTextBody("cutwatertone",map.get("cutwatertone"),strContent);
              HttpEntity httpEntity =  params.build();
              httpPost.setEntity(httpEntity);
              try {
                  StringBuilder sb = new StringBuilder();
                  String line;
                  HttpResponse httpResponse = httpclient.execute(httpPost);
                  InputStream inputStream = httpResponse.getEntity().getContent();
                  BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"UTF-8"));
                  while ((line = br.readLine()) != null) {
                      sb.append(line);
                  }
                  rspMsg = URLDecoder.decode(sb.toString(),"UTF-8");
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return rspMsg;
      }
      

      对于这个发送文件的封装方法,网上真的很多,但有些就是封装了file的参数,没有其他普通参数的封装,还有要主要的就是发送文件必须要把文件转换成流才行。当时做发送文件和参数到电信接口时,就在网上找了好多好多方法,都不行…;其实这也是再网上找的,不同的是在创建请求体时,使用的是一个创建者设计模式,有点绕。但是大致步骤还是一样的。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^