如何使用HttpClient模拟浏览器GET POST

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用HttpClient模拟浏览器GET POST相关的知识,希望对你有一定的参考价值。

JAVA-用HttpClient来模拟浏览器GET,POST
一般的情况下我们都是使用IE或者Navigator浏览器来访问一个WEB服务器,用来浏览页面查看信息或者提交一些数据等等。所访问的这些页面 有的仅仅是一些普通的页面,有的需要用户登录后方可使用,或者需要认证以及是一些通过加密方式传输,例如HTTPS。目前我们使用的浏览器处理这些情况都 不会构成问题。不过你可能在某些时候需要通过程序来访问这样的一些页面,比如从别人的网页中“偷”一些数据;利用某些站点提供的页面来完成某种功能,例如 说我们想知道某个手机号码的归属地而我们自己又没有这样的数据,因此只好借助其他公司已有的网站来完成这个功能,这个时候我们需要向网页提交手机号码并从 返回的页面中解析出我们想要的数据来。如果对方仅仅是一个很简单的页面,那我们的程序会很简单,本文也就没有必要大张旗鼓的在这里浪费口舌。但是考虑到一 些服务授权的问题,很多公司提供的页面往往并不是可以通过一个简单的URL就可以访问的,而必须经过注册然后登录后方可使用提供服务的页面,这个时候就涉 及到COOKIE问题的处理。我们知道目前流行的动态网页技术例如ASP、JSP无不是通过COOKIE来处理会话信息的。为了使我们的程序能使用别人所 提供的服务页面,就要求程序首先登录后再访问服务页面,这过程就需要自行处理cookie,想想当你用 java.net.HttpURLConnection来完成这些功能时是多么恐怖的事情啊!况且这仅仅是我们所说的顽固的WEB服务器中的一个很常见的 “顽固”!再有如通过HTTP来上传文件呢?不需要头疼,这些问题有了“它”就很容易解决了!
我们不可能列举所有可能的顽固,我们会 针对几种最常见的问题进行处理。当然了,正如前面说到的,如果我们自己使用java.net.HttpURLConnection来搞定这些问题是很恐怖 的事情,因此在开始之前我们先要介绍一下一个开放源码的项目,这个项目就是Apache开源组织中的httpclient,它隶属于Jakarta的 commons项目,目前的版本是2.0RC2。commons下本来已经有一个net的子项目,但是又把httpclient单独提出来,可见http 服务器的访问绝非易事。
Commons-httpclient项目就是专门设计来简化HTTP客户端与服务器进行各种通讯编程。通过它可 以让原来很头疼的事情现在轻松的解决,例如你不再管是HTTP或者HTTPS的通讯方式,告诉它你想使用HTTPS方式,剩下的事情交给 httpclient替你完成。本文会针对我们在编写HTTP客户端程序时经常碰到的几个问题进行分别介绍如何使用httpclient来解决它们,为了 让读者更快的熟悉这个项目我们最开始先给出一个简单的例子来读取一个网页的内容,然后循序渐进解决掉前进中的所有问题。
1. 读取网页(HTTP/HTTPS)内容
下面是我们给出的一个简单的例子用来访问某个页面
/**//*
* Created on 2003-12-14 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/** *//**
* 最简单的HTTP客户端,用来演示通过GET或者POST方式访问某个页面
* @author Liudong
*/
public class SimpleClient ...
public static void main(String[] args) throws IOException
...
HttpClient client = new HttpClient();
//设置代理服务器地址和端口
//client.getHostConfiguration().setProxy("proxy_host_addr",proxy_port);
//使用GET方法,如果服务器需要通过HTTPS连接,那只需要将下面URL中的http换成https
HttpMethod method = new GetMethod("http://java.sun.com";);
//使用POST方法
//HttpMethod method = new PostMethod("http://java.sun.com";);
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印返回的信息
System.out.println(method.getResponseBodyAsString());
//释放连接
method.releaseConnection();


在这个例子中首先创建一个HTTP客户端(HttpClient)的实例,然后选择提交的方法是GET或者POST,最后在HttpClient实 例上执行提交的方法,最后从所选择的提交方法中读取服务器反馈回来的结果。这就是使用HttpClient的基本流程。其实用一行代码也就可以搞定整个请 求的过程,非常的简单!
2. 以GET或者POST方式向网页提交参数
其实前面一个最简单的示例中我们已经介绍了如何使用 GET或者POST方式来请求一个页面,本小节与之不同的是多了提交时设定页面所需的参数,我们知道如果是GET的请求方式,那么所有参数都直接放到页面 的URL后面用问号与页面地址隔开,每个参数用&隔开,例如:http://java.sun.com/?name=liudong&mobile=123456,但是当使用POST方法时就会稍微有一点点麻烦。本小节的例子演示向如何查询手机号码所在的城市,代码如下:
/**//*
* Created on 2003-12-7 by Liudong
*/
package http.demo;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
/** *//**
* 提交参数演示
* 该程序连接到一个用于查询手机号码所属地的页面
* 以便查询号码段1330227所在的省份以及城市
* @author Liudong
*/
public class SimpleHttpClient ...
public static void main(String[] args) throws IOException
...
HttpClient client = new HttpClient();
client.getHostConfiguration().setHost("www.imobile.com.cn", 80, "http");
HttpMethod method = getPostMethod();//使用POST方式提交数据
client.executeMethod(method);
//打印服务器返回的状态
System.out.println(method.getStatusLine());
//打印结果页面
String response = new String(method.getResponseBodyAsString().getBytes("8859_1"));
//打印返回的信息
System.out.println(response);
method.releaseConnection();

/** *//**
* 使用GET方式提交数据
* @return
*/
private static HttpMethod getGetMethod()...
return new GetMethod("/simcard.php?simcard=1330227");

/** *//**
* 使用POST方式提交数据
* @return
*/
private static HttpMethod getPostMethod()...
PostMethod post = new PostMethod("/simcard.php");
NameValuePair simcard = new NameValuePair("simcard","1330227");
post.setRequestBody(new NameValuePair[] ... simcard);
return post;

参考技术A CloseableHttpClient httpClient = HttpClients.createDefault();//创建Httpclient 对象
Httpget httpget = new Httpget(url);//创建get请求
Httppost httppost = new Httppost(url);//创建post请求
httpresponse httpresponse=httpClient.execute(httpget or httppost); //发送请求并用response接收
EntityUtils.toString(httpresponse.getEntity);//获取返回内容

如何使 .net HttpClient 使用 http 2.0?

【中文标题】如何使 .net HttpClient 使用 http 2.0?【英文标题】:How to make the .net HttpClient use http 2.0? 【发布时间】:2015-12-17 13:24:38 【问题描述】:

我有一个托管在 IIS 10(Windows Server 2016)上的 asp.net Web api。当我从 Microsoft Edge 浏览器向它发出 GET 请求时,我看到在 IIS 日志中使用了 HTTP 2.0

2015-09-20 21:57:59 100.76.48.17 GET /RestController/Native - 443 - 73.181.195.76 HTTP/2.0 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/42.0.2311.135+Safari/537.36+Edge/12.10240 - 200 0 0 7299

但是,当通过.net 4.6 client 发出GET 请求时,如下所示,

using (var client = new HttpClient())

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

我在服务器日志中看到以下HTTP 1.1登录

2015-09-20 20:57:41 100.76.48.17 GET /RestController/Native - 443 - 131.107.160.196 HTTP/1.1 - - 200 0 0 707

如何让 .net 客户端使用 HTTP/2.0?

【问题讨论】:

【参考方案1】:

HttpClient 还不支持 HTTP/2。它将在下一个版本中提供(代号 KATANA)。这是link to their source code for the next release。

到那时,您可以实现自己的实现 HTTP/2 的 HttpMessageHandler 对象并将其传递给 HttpClient 的构造函数(您可能可以使用来自 KATANA 的源代码)。

【讨论】:

您链接到的 repo 似乎仅适用于服务器组件,而不是客户端(有一个测试客户端,它使用 TcpClient,但不是真正的 HttpClient) @RacilHilan 谢谢你的回答。 “您可以实现自己的实现 HTTP/2 的 HttpMessageHandler 对象”关于您的评论。你能详细说明一下吗? @RashminJaviya 您可以使用我的答案中的链接从他们的源代码中复制代码并将其添加到您的项目中。请记住,代码来自开发,因此您必须自己进行所有测试和可能的修复。显然,这不是一项简单的任务,但当被问到这个问题时,这是唯一的方法。现在,情况发生了变化。如果符合您的需要,请参阅下面 Oliver 的回答。【参考方案2】:

HTTP/2 看起来将在 .NET 4.6.2 的 C# 客户端调用中得到支持

https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx

HTTP/2 支持(Windows 10)

HTTP/2 是 HTTP 协议的新版本,它提供了更好的 连接利用率(客户端和服务器之间的往返次数减少), 导致用户的网页加载延迟更低。网页(如 与服务相反)从 HTTP/2 中受益最多,因为该协议 针对作为单个请求的一部分请求的多个工件进行优化 经验。 HTTP/2 支持已添加到 .NET 中的 ASP.NET 框架 4.6。因为网络功能存在于多个 层,Windows、IIS 和 ASP.NET 中需要新功能 启用 HTTP/2。您必须在 Windows 10 上运行才能使用 HTTP/2 ASP.NET。

Windows 10 Universal 也支持 HTTP/2,并且默认开启 使用 System.Net.Http.HttpClient 的 Windows 平台 (UWP) 应用 API。

【讨论】:

这只是服务器端,不是客户端。 是的,我正在运行安装了 .net 4.7 的 VS2017,我只看到 HTTP.version 1.0 和 1.1。 看到这条评论:To use HTTP/2 protocol support, you must use .NET Core. You must also use a supported version of Windows 10. And you need to manually specify HttpRequestMessage.Version = new Version(2,0); You can also use the separate System.Net.Http.WinHttpHandler package which provides an alternate handler for HttpClient. You need to create that WinHttpHandler and pass it into the constructor of HttpClient. This WinHttpHandler package is supported on both .NET Core .NET Framework 在这里:github.com/dotnet/corefx/issues/4870 也在同一页:you can use WinHttpHandler on .NET Framework. You must only use the SendAsync() methods from HttpClient. Those are the only ones that allow you to pass in an HttpRequestMessage. Other methods, use a default HttpRequestMessage that uses Version(1,1) only. You have to set the .Version field in HttpRequestMessage to 2.0 as indicated. You have to use a current version of Windows 10.【参考方案3】:

1.确保您使用的是最新版本的Windows 10

2.安装WinHttpHandler

Install-Package System.Net.Http.WinHttpHandler

3.扩展WinHttpHandler添加http2.0支持:

public class Http2CustomHandler : WinHttpHandler

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    
        request.Version = new Version("2.0");
        return base.SendAsync(request, cancellationToken);
    

4.将上述处理程序传递给 HttpClient 构造函数

using (var httpClient = new HttpClient(new Http2CustomHandler()))

      // your custom code

【讨论】:

同意,这仍然是在完整的 .net 框架中获得对 HttpClient 的 http2.0 支持的唯一方法 是的,这行得通-谢谢。试图理解为什么 4.72 框架和 win 10 上的 httpclient 在 http2 上不起作用!看起来很疯狂,它不在核心库中,顺便说一句,它安装了很多依赖项。从 4.6 开始测试。 非跨平台 那行得通。但是如果需要管理CookieContainer,还需要将CookieUsePolicy设置为CookieUsePolicy.UseSpecifiedCookieContainer【参考方案4】:

除了WinHttpHandler(as described in Shawinder Sekhon's answer),.NET Core 3.0 中默认includes HTTP/2 supportSocketsHttpHandler(#30740)。由于 the default 在 UWP 之外仍然是 HTTP/1.1,因此必须在每个请求上指定 Version。这可以根据每个请求的需要完成:

using (var client = new HttpClient())

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.SendAsync(
        new HttpRequestMessage(HttpMethod.Get, "RestController/Native")
        
            Version = HttpVersion.Version20,
        );
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

或者对所有请求使用自定义HttpMessageHandler,例如:

public class ForceHttp2Handler : DelegatingHandler

    public ForceHttp2Handler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    
    

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    
        request.Version = HttpVersion.Version20;
        return base.SendAsync(request, cancellationToken);
    

可以委托给SocketsHttpHandlerWinHttpHandler或任何其他支持HTTP/2的HttpMessageHandler

using (var client = new HttpClient(new ForceHttp2Handler(new SocketsHttpHandler())))

    client.BaseAddress = new Uri("https://myapp.cloudapp.net/");

    HttpResponseMessage response = await client.GetAsync("RestController/Native");
    if (response.IsSuccessStatusCode)
    
        await response.Content.CopyToAsync(new MemoryStream(buffer));
    

【讨论】:

以上是关于如何使用HttpClient模拟浏览器GET POST的主要内容,如果未能解决你的问题,请参考以下文章

Android--httpclient模拟post请求和get请求

httpclient模拟登陆成功后在浏览器中打开登陆后的页面

HttpClient模拟get,post请求并发送请求参数(json等)

如何通过python twisted HTTPClient生成POST和GET请求?

解决 HttpClient 模拟 http 的get 请求后 ,出现 403 错误

如何使 .net HttpClient 使用 http 2.0?