【问题标题】:commons httpclient - Adding query string parameters to GET/POST requestcommons httpclient - 将查询字符串参数添加到 GET/POST 请求
【发布时间】:2012-04-12 00:35:29
【问题描述】:

我正在使用 commons HttpClient 对 Spring servlet 进行 http 调用。我需要在查询字符串中添加一些参数。所以我做了以下事情:

HttpRequestBase request = new HttpGet(url);
HttpParams params = new BasicHttpParams();
params.setParameter("key1", "value1");
params.setParameter("key2", "value2");
params.setParameter("key3", "value3");
request.setParams(params);
HttpClient httpClient = new DefaultHttpClient();
httpClient.execute(request);

但是,当我尝试使用 servlet 读取参数时

((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getParameter("key");

它返回空值。实际上 parameterMap 是完全空的。当我在创建 HttpGet 请求之前手动将参数附加到 url 时,参数在 servlet 中可用。当我使用附加了 queryString 的 URL 从浏览器中点击 servlet 时也是如此。

这里有什么错误?在 httpclient 3.x 中,GetMethod 有一个 setQueryString() 方法来附加查询字符串。 4.x 中的等价物是什么?

【问题讨论】:

    标签: java apache-httpclient-4.x


    【解决方案1】:

    我正在使用 Java 8 和 apache httpclient 4.5.13

    HashMap<String, String> customParams = new HashMap<>();
    customParams.put("param1", "ABC");
    customParams.put("param2", "123");
    
    URIBuilder uriBuilder = new URIBuilder(baseURL);
    
    for (String paramKey : customParams.keySet()) {
        uriBuilder.addParameter(paramKey, customParams.get(paramKey));
    }
    
    System.out.println(uriBuilder.build().toASCIIString()); // ENCODED URL
    System.out.println(uriBuilder.build().toString); // NORMAL URL
    

    DTO 的完整示例

    public class HttpResponseDTO {
        private Integer statusCode;
        private String body;
        private String errorMessage;
        
        public Integer getStatusCode() {
            return statusCode;
        }
        public void setStatusCode(Integer statusCode) {
            this.statusCode = statusCode;
        }
        public String getBody() {
            return body;
        }
        public void setBody(String body) {
            this.body = body;
        }
        public String getErrorMessage() {
            return errorMessage;
        }
        public void setErrorMessage(String errorMessage) {
            this.errorMessage = errorMessage;
        }
    }
    
        /**
         * 
         * @param destinationURL
         * @param params
         * @param headers
         * @return HttpResponseDTO
         */
        public static HttpResponseDTO get(String baseURL, Boolean encodeURL, HashMap<String, String> params, HashMap<String, String> headers) {
    
            final HttpResponseDTO httpResponseDTO = new HttpResponseDTO();      
    
            // ADD PARAMS IF
            if (params != null && Boolean.FALSE.equals(params.isEmpty())) {
                URIBuilder uriBuilder;
                try {
                    uriBuilder = new URIBuilder(baseURL);
    
                    for (String paramKey : params.keySet()) {
                        uriBuilder.addParameter(paramKey, params.get(paramKey));
                    }
    
                    // CODIFICAR URL ?
                    if (Boolean.TRUE.equals(encodeURL)) {
                        baseURL = uriBuilder.build().toASCIIString();
                    } else {
                        baseURL = uriBuilder.build().toString();
                    }
                } catch (URISyntaxException e) {
                    httpResponseDTO.setStatusCode(500);
                    httpResponseDTO.setErrorMessage("ERROR AL CODIFICAR URL: " + e.getMessage());
                    return httpResponseDTO;
                }
            }
    
    
            // HACER PETICION HTTP
            try (CloseableHttpClient httpClient = HttpClients.createDefault()) {            
                final HttpGet get = new HttpGet(baseURL);   
    
                // ADD HEADERS
                if (headers != null && Boolean.FALSE.equals(headers.isEmpty())) {           
                    for (String headerKey : headers.keySet()) {
                        get.setHeader(headerKey, headers.get(headerKey));
                    }           
                }
    
                try (CloseableHttpResponse response = httpClient.execute(get);) {
                    HttpEntity httpEntity = response.getEntity();
                    if (httpEntity != null) {
                        httpResponseDTO.setBody(EntityUtils.toString(httpEntity));
                        httpResponseDTO.setStatusCode(response.getStatusLine().getStatusCode());
                    }
                } catch(Exception e) {
                    httpResponseDTO.setStatusCode(500);
                    httpResponseDTO.setErrorMessage(e.getMessage());
                    return httpResponseDTO;
                }
            } catch(Exception e) {
                httpResponseDTO.setStatusCode(500);
                httpResponseDTO.setErrorMessage(e.getMessage());
                return httpResponseDTO;
            }
    
            return httpResponseDTO;
        }
    

    【讨论】:

    • 这基本上是accepted answer,但带有一些用于测试的示例代码。
    【解决方案2】:

    这就是我实现 URL 构建器的方式。 我创建了一个服务类来提供 URL 的参数

    public interface ParamsProvider {
    
        String queryProvider(List<BasicNameValuePair> params);
    
        String bodyProvider(List<BasicNameValuePair> params);
    }
    
    

    方法的实现如下

    @Component
    public class ParamsProviderImp implements ParamsProvider {
        @Override
        public String queryProvider(List<BasicNameValuePair> params) {
            StringBuilder query = new StringBuilder();
            AtomicBoolean first = new AtomicBoolean(true);
            params.forEach(basicNameValuePair -> {
                if (first.get()) {
                    query.append("?");
                    query.append(basicNameValuePair.toString());
                    first.set(false);
                } else {
                    query.append("&");
                    query.append(basicNameValuePair.toString());
                }
            });
            return query.toString();
        }
    
        @Override
        public String bodyProvider(List<BasicNameValuePair> params) {
            StringBuilder body = new StringBuilder();
            AtomicBoolean first = new AtomicBoolean(true);
            params.forEach(basicNameValuePair -> {
                if (first.get()) {
                    body.append(basicNameValuePair.toString());
                    first.set(false);
                } else {
                    body.append("&");
                    body.append(basicNameValuePair.toString());
                }
            });
            return body.toString();
        }
    }
    
    

    当我们需要 URL 的查询参数时,我只需调用服务并构建它。 示例如下。

    Class Mock{
    @Autowired
    ParamsProvider paramsProvider;
     String url ="http://www.google.lk";
    // For the query params price,type
     List<BasicNameValuePair> queryParameters = new ArrayList<>();
     queryParameters.add(new BasicNameValuePair("price", 100));
     queryParameters.add(new BasicNameValuePair("type", "L"));
    url = url+paramsProvider.queryProvider(queryParameters);
    // You can use it in similar way to send the body params using the bodyProvider
    
    }
    
    

    【讨论】:

      【解决方案3】:

      我正在使用 httpclient 4.4。

      对于 solr 查询,我使用了以下方式,并且成功了。

      NameValuePair nv2 = new BasicNameValuePair("fq","(active:true) AND (category:Fruit OR category1:Vegetable)");
      nvPairList.add(nv2);
      NameValuePair nv3 = new BasicNameValuePair("wt","json");
      nvPairList.add(nv3);
      NameValuePair nv4 = new BasicNameValuePair("start","0");
      nvPairList.add(nv4);
      NameValuePair nv5 = new BasicNameValuePair("rows","10");
      nvPairList.add(nv5);
      
      HttpClient client = HttpClientBuilder.create().build();
      HttpGet request = new HttpGet(url);
      URI uri = new URIBuilder(request.getURI()).addParameters(nvPairList).build();
                  request.setURI(uri);
      
      HttpResponse response = client.execute(request);    
      if (response.getStatusLine().getStatusCode() != 200) {
      
      }
      
      BufferedReader br = new BufferedReader(
                                   new InputStreamReader((response.getEntity().getContent())));
      
      String output;
      System.out.println("Output  .... ");
      String respStr = "";
      while ((output = br.readLine()) != null) {
          respStr = respStr + output;
          System.out.println(output);
      }
      

      【讨论】:

      • 这个答案将受益于更多的解释
      • 这个答案对我的情况非常有用,因为我找不到使用完整 URI 初始化 URIBuilder 的方法,例如 http://myserver/apipath。当用它初始化时,URIBuilder 只使用了http://myserver 而忽略了/apipath。 URI 是从外部提供的,所以我不想手动解析它只是为了使用 URIBuilder。
      【解决方案4】:

      以下是使用 HttpClient 4.2 及更高版本添加查询字符串参数的方法:

      URIBuilder builder = new URIBuilder("http://example.com/");
      builder.setParameter("parts", "all").setParameter("action", "finish");
      
      HttpPost post = new HttpPost(builder.build());
      

      生成的 URI 如下所示:

      http://example.com/?parts=all&action=finish
      

      【讨论】:

        【解决方案5】:

        这种方法可以,但不适用于动态获取参数时,有时是 1、2、3 或更多,就像 SOLR 搜索查询(例如)

        这是一个更灵活的解决方案。粗制滥造,但可以精炼。

        public static void main(String[] args) {
        
            String host = "localhost";
            String port = "9093";
        
            String param = "/10-2014.01?description=cars&verbose=true&hl=true&hl.simple.pre=<b>&hl.simple.post=</b>";
            String[] wholeString = param.split("\\?");
            String theQueryString = wholeString.length > 1 ? wholeString[1] : "";
        
            String SolrUrl = "http://" + host + ":" + port + "/mypublish-services/carclassifications/" + "loc";
        
            GetMethod method = new GetMethod(SolrUrl );
        
            if (theQueryString.equalsIgnoreCase("")) {
                method.setQueryString(new NameValuePair[]{
                });
            } else {
                String[] paramKeyValuesArray = theQueryString.split("&");
                List<String> list = Arrays.asList(paramKeyValuesArray);
                List<NameValuePair> nvPairList = new ArrayList<NameValuePair>();
                for (String s : list) {
                    String[] nvPair = s.split("=");
                    String theKey = nvPair[0];
                    String theValue = nvPair[1];
                    NameValuePair nameValuePair = new NameValuePair(theKey, theValue);
                    nvPairList.add(nameValuePair);
                }
                NameValuePair[] nvPairArray = new NameValuePair[nvPairList.size()];
                nvPairList.toArray(nvPairArray);
                method.setQueryString(nvPairArray);       // Encoding is taken care of here by setQueryString
        
            }
        }
        

        【讨论】:

        • 获取方法?它来自 httpclient 吗?因为问题是关于它的。
        • 是的,来自 org.apache.commons.httpclient.methods。
        • 啊是的,不过好像是3.x版本的,4.x现在是org.apache.http.client.methods.HttpGet
        【解决方案6】:

        如果您想在创建请求后添加查询参数,请尝试将 HttpRequest 强制转换为 HttpBaseRequest。然后你可以改变被转换的请求的 URI:

        HttpGet someHttpGet = new HttpGet("http://google.de");
        
        URI uri = new URIBuilder(someHttpGet.getURI()).addParameter("q",
                "That was easy!").build();
        
        ((HttpRequestBase) someHttpGet).setURI(uri);
        

        【讨论】:

          【解决方案7】:

          HttpParams 接口不是用于指定查询字符串参数,而是用于指定HttpClient 对象的运行时行为。

          如果要传递查询字符串参数,需要自己在URL上组装,例如

          new HttpGet(url + "key1=" + value1 + ...);
          

          记得先对值进行编码(使用URLEncoder)。

          【讨论】:

          • 请求对象已经创建后,有没有办法添加查询字符串参数?如果没有,是否有另一种标准方法可以将参数传递给任何请求方法(GET/PUT/POST)的 servlet?
          猜你喜欢
          • 2014-06-15
          • 2013-04-20
          • 1970-01-01
          • 2019-11-29
          • 1970-01-01
          • 2010-09-18
          • 1970-01-01
          • 2021-03-22
          • 1970-01-01
          相关资源
          最近更新 更多