java - 如何使用 HttpURLConnection 以与 Apache HttpClient lib 相同的方式发出 POST 请求

标签 java httpurlconnection apache-httpclient-4.x

我正在尝试向网站发出 POST 请求。作为对 POST 请求的响应,我需要一些 JSON 数据。

使用 Apache 的 HttpClient 库,我可以毫无问题地执行此操作。响应数据是 JSON,所以我只是解析它。

package com.mydomain.myapp;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class MyApp {

    private static String extract(String patternString, String target) {

        Pattern pattern = Pattern.compile(patternString);
        Matcher matcher = pattern.matcher(target);
        matcher.find();
        return matcher.group(1);
    }

    private String getResponse(InputStream stream) throws Exception {

        BufferedReader in = new BufferedReader(new InputStreamReader(stream));
        String inputLine;
        StringBuffer responseStringBuffer = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            responseStringBuffer.append(inputLine);
        }
        in.close();
        return responseStringBuffer.toString();
    }

    private final static String BASE_URL = "https://www.volkswagen-car-net.com";
    private final static String BASE_GUEST_URL = "/portal/en_GB/web/guest/home";

    private void run() throws Exception {

        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(BASE_URL + BASE_GUEST_URL);
        CloseableHttpResponse getResponse = client.execute(httpGet);
        HttpEntity responseEntity = getResponse.getEntity();
        String data = getResponse(responseEntity.getContent());
        EntityUtils.consume(responseEntity);

        String csrf = extract("<meta name=\"_csrf\" content=\"(.*)\"/>", data);
        System.out.println(csrf);

        HttpPost post = new HttpPost(BASE_URL + "/portal/web/guest/home/-/csrftokenhandling/get-login-url");
        post.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        post.setHeader("User-Agent'", "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36");
        post.setHeader("Referer", BASE_URL + "/portal");
        post.setHeader("X-CSRF-Token", csrf);

        CloseableHttpResponse postResponse = client.execute(post);
        HttpEntity postResponseEntity = postResponse.getEntity();
        String postData = getResponse(postResponseEntity.getContent());
        System.out.println(postData);
        EntityUtils.consume(postResponseEntity);
        postResponse.close();
    }

    public static void main(String[] args) throws Exception {

        MyApp myApp = new MyApp();
        myApp.run();
    }
}

但是我不能在我的项目中使用 HttpClient 库。我需要能够对“仅”HttpURLConnection 执行相同的操作。

但是 HttpClient 库有一些我无法理解的魔力。因为使用 HttpURLConnection 对我的 POST 请求的响应只是重定向到不同的网页。

有人能给我指出正确的方向吗?

这是我当前的 HttpURLConnection 尝试:

package com.mydomain.myapp;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyApp {

    private static String extract(String patternString, String target) {

        Pattern pattern = Pattern.compile(patternString);
        Matcher matcher = pattern.matcher(target);
        matcher.find();
        return matcher.group(1);
    }

    private final static String BASE_URL = "https://www.volkswagen-car-net.com";
    private final static String BASE_GUEST_URL = "/portal/en_GB/web/guest/home";

    private String getResponse(InputStream stream) throws Exception {

        BufferedReader in = new BufferedReader(new InputStreamReader(stream));
        String inputLine;
        StringBuffer responseStringBuffer = new StringBuffer();
        while ((inputLine = in.readLine()) != null) {
            responseStringBuffer.append(inputLine);
        }
        in.close();
        return responseStringBuffer.toString();
    }

    private String getResponse(HttpURLConnection connection) throws Exception {
        return getResponse(connection.getInputStream());
    }

    private void run() throws Exception {

        HttpURLConnection getConnection1;
        URL url = new URL(BASE_URL + BASE_GUEST_URL);
        getConnection1 = (HttpURLConnection) url.openConnection();
        getConnection1.setRequestMethod("GET");
        if (getConnection1.getResponseCode() != HttpURLConnection.HTTP_OK) {
            throw new Exception("Request failed");
        }

        String response = getResponse(getConnection1);
        getConnection1.disconnect();

        String csrf = extract("<meta name=\"_csrf\" content=\"(.*)\"/>", response);
        System.out.println(csrf);

        HttpURLConnection postRequest;
        URL url2 = new URL(BASE_URL + "/portal/web/guest/home/-/csrftokenhandling/get-login-url");
        postRequest = (HttpURLConnection) url2.openConnection();
        postRequest.setDoOutput(true);
        postRequest.setRequestMethod("POST");
        postRequest.setInstanceFollowRedirects(false);

        postRequest.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        postRequest.setRequestProperty("User-Agent'", "Mozilla/5.0 (Linux; Android 6.0.1; D5803 Build/23.5.A.1.291; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36");
        postRequest.setRequestProperty("Referer", BASE_URL + "/portal");
        postRequest.setRequestProperty("X-CSRF-Token", csrf);

        postRequest.disconnect();
    }

    public static void main(String[] args) throws Exception {

        MyApp myApp = new MyApp();
        myApp.run();
    }
}

最佳答案

感谢优秀的程序员资源,例如MKYong(你知道你之前访问过他的网站 ;-)),我会回顾一下它的要点以防 link永远下降。

要点:

The HttpURLConnection‘s follow redirect is just an indicator, in fact it won’t help you to do the “real” http redirection, you still need to handle it manually.
If a server is redirected from the original URL to another URL, the response code should be 301: Moved Permanently or 302: Temporary Redirect. And you can get the new redirected url by reading the “Location” header of the HTTP response header.

For example, access to the normal HTTP twitter website – http://www.twitter.com , it will auto redirect to the HTTPS twitter website – https://www.twitter.com.

示例代码

package com.mkyong.http;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpRedirectExample {

  public static void main(String[] args) {

    try {

    String url = "http://www.twitter.com";

    URL obj = new URL(url);
    HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
    conn.setReadTimeout(5000);
    conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
    conn.addRequestProperty("User-Agent", "Mozilla");
    conn.addRequestProperty("Referer", "google.com");

    System.out.println("Request URL ... " + url);

    boolean redirect = false;

    // normally, 3xx is redirect
    int status = conn.getResponseCode();
    if (status != HttpURLConnection.HTTP_OK) {
        if (status == HttpURLConnection.HTTP_MOVED_TEMP
            || status == HttpURLConnection.HTTP_MOVED_PERM
                || status == HttpURLConnection.HTTP_SEE_OTHER)
        redirect = true;
    }

    System.out.println("Response Code ... " + status);

    if (redirect) {

        // get redirect url from "location" header field
        String newUrl = conn.getHeaderField("Location");

        // get the cookie if need, for login
        String cookies = conn.getHeaderField("Set-Cookie");

        // open the new connnection again
        conn = (HttpURLConnection) new URL(newUrl).openConnection();
        conn.setRequestProperty("Cookie", cookies);
        conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
        conn.addRequestProperty("User-Agent", "Mozilla");
        conn.addRequestProperty("Referer", "google.com");

        System.out.println("Redirect to URL : " + newUrl);

    }

    BufferedReader in = new BufferedReader(
                              new InputStreamReader(conn.getInputStream()));
    String inputLine;
    StringBuffer html = new StringBuffer();

    while ((inputLine = in.readLine()) != null) {
        html.append(inputLine);
    }
    in.close();

    System.out.println("URL Content... \n" + html.toString());
    System.out.println("Done");

    } catch (Exception e) {
    e.printStackTrace();
    }

  }

}

关于java - 如何使用 HttpURLConnection 以与 Apache HttpClient lib 相同的方式发出 POST 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53091231/

相关文章:

java - Spring MVC。渲染布局

java - StackOverFlowError SpannableString 是什么意思?

java - 带有 AsyncTask 的 HttpURLConnection 太慢 (Android)

java - HttpClient.getParams() 已弃用。我应该改用什么?

java - Android HttpUrlConneion上传大文件导致413,但getResponseCode无法返回并抛出另一个异常

java - 无法获取父级的哈希码并将其设置为子级的变量

java - Android中的HttpUrlConnection设置范围被忽略

Java bug - 无法将授权添加到 HttpURLConnection set/addRequestProperty()

java - 异常 : javax.net.ssl.SSLPeerUnverifiedException:对等体未通过身份验证

java - 如何在 Rest Assured 中为失败的 REST 调用实现重试逻辑