使用 java.net.URLConnection
在这里经常被问到,而oracle教程对它的描述过于简洁。
该教程基本上只展示了如何启动get请求并读取响应。它没有在任何地方解释如何使用它来执行post请求、设置请求头、读取响应头、处理cookie、提交html表单、上载文件等。
那么,我该怎么用 java.net.URLConnection
启动并处理“高级”http请求?
使用 java.net.URLConnection
在这里经常被问到,而oracle教程对它的描述过于简洁。
该教程基本上只展示了如何启动get请求并读取响应。它没有在任何地方解释如何使用它来执行post请求、设置请求头、读取响应头、处理cookie、提交html表单、上载文件等。
那么,我该怎么用 java.net.URLConnection
启动并处理“高级”http请求?
7条答案
按热度按时间j2datikz1#
更新
新的http客户机与java9一起提供,但是作为名为
jdk.incubator.httpclient
. 孵化器模块是一种将非最终API交给开发人员的方法,而这些API在将来的版本中要么最终完成,要么删除。在Java9中,您可以发送
GET
请求如下:然后你可以检查返回的
HttpResponse
:因为这个新的http客户端
java.httpclient
jdk.incubator.httpclient
模块中声明此依赖关系module-info.java
文件:3hvapo4f2#
受这个问题和其他问题的启发,我创建了一个最小的开源基本http客户机,它体现了这里发现的大多数技术。
googlehttpjava客户端也是一个很好的开源资源。
ffvjumwh3#
我建议您看看kevinsawicki/http请求的代码,它基本上是在
HttpUrlConnection
它提供了一个简单得多的api,以防您现在只想发出请求,或者您可以查看源代码(它不是太大)以了解如何处理连接。示例:制作
GET
内容类型为的请求application/json
以及一些查询参数:ejk8hzay4#
有两个选项可以用于http url点击:get/post
获取请求:-
发布请求:-
nbysray55#
首先是事先声明:发布的代码片段都是基本示例。你需要处理一些琐碎的事情
IOException
s和RuntimeException
就像NullPointerException
,ArrayIndexOutOfBoundsException
和你的配偶。准备
我们首先需要至少知道url和字符集。参数是可选的,取决于功能要求。
查询参数必须在
name=value
格式和连接方式&
. 通常,您还可以使用指定的字符集对查询参数进行url编码URLEncoder#encode()
.这个
String#format()
只是为了方便。当我需要字符串连接运算符时,我更喜欢它+
不止两次。使用(可选)查询参数触发http get请求
这是一件小事。这是默认的请求方法。
任何查询字符串都应该使用
?
. 这个Accept-Charset
标头可能会提示服务器参数的编码方式。如果不发送任何查询字符串,则可以将Accept-Charset
头球离开。如果您不需要设置任何标题,那么您甚至可以使用URL#openStream()
快捷方式方法。不管怎样,如果对方是
HttpServlet
,那么doGet()
方法,参数将由HttpServletRequest#getParameter()
.出于测试目的,您可以将响应正文打印到stdout,如下所示:
使用查询参数触发http post请求
设置
URLConnection#setDoOutput()
至true
隐式地将请求方法设置为post。作为web窗体的标准http post类型为application/x-www-form-urlencoded
其中,查询字符串被写入请求主体。注意:每当您想以编程方式提交html表单时,不要忘记
name=value
任何一对<input type="hidden">
元素,当然还有name=value
一对<input type="submit">
元素,您希望以编程方式“按下”该元素(因为服务器端通常使用该元素来区分是否按下了按钮,如果是,则是哪个按钮)。你也可以施展获得的技能
URLConnection
至HttpURLConnection
使用它的HttpURLConnection#setRequestMethod()
相反。但是,如果您试图使用输出连接,您仍然需要设置URLConnection#setDoOutput()
至true
.不管怎样,如果对方是
HttpServlet
,那么doPost()
方法,参数将由HttpServletRequest#getParameter()
.实际上触发了http请求
您可以使用
URLConnection#connect()
,但当您希望获取有关http响应的任何信息(例如使用URLConnection#getInputStream()
等等。上面的例子正是这样做的,所以connect()
打电话其实是多余的。正在收集http响应信息
http响应状态:
你需要一个
HttpURLConnection
在这里。必要时先浇铸。http响应头:
http响应编码:
当
Content-Type
包含charset
参数,则响应主体可能是基于文本的,我们希望使用服务器端指定的字符编码来处理响应主体。维护会话
服务器端会话通常由cookie支持。某些web窗体要求您登录和/或由会话跟踪。你可以用
CookieHandler
维护cookies的api。你需要准备一个CookieManager
用一个CookiePolicy
的ACCEPT_ALL
在发送所有http请求之前。请注意,这并不是在所有情况下都能正常工作。如果失败了,那么最好是手动收集并设置cookie头。你基本上需要抓住所有
Set-Cookie
来自登录或第一个GET
请求,然后将其传递给后续请求。这个
split(";", 2)[0]
有没有办法去掉与服务器端无关的cookie属性expires
,path
或者,您也可以使用cookie.substring(0, cookie.indexOf(';'))
而不是split()
.流模式
这个
HttpURLConnection
默认情况下,将在实际发送请求之前缓冲整个请求体,而不管您是否已使用设置了固定的内容长度connection.setRequestProperty("Content-Length", contentLength);
. 这可能导致OutOfMemoryException
当您同时发送大量post请求时(例如上载文件)。为了避免这种情况,您需要设置HttpURLConnection#setFixedLengthStreamingMode()
.但是如果内容长度确实事先不知道,那么可以通过设置
HttpURLConnection#setChunkedStreamingMode()
相应地。这将设置httpTransfer-Encoding
标题至chunked
这将强制请求主体成批发送。下面的示例将以1kb的块发送正文。用户代理
一个请求可能会返回一个意外的响应,而它在一个真正的web浏览器上运行良好。服务器端可能正在阻止基于
User-Agent
请求标头。这个URLConnection
将默认设置为Java/1.6.0_19
最后一部分显然是jre版本。您可以按如下方式覆盖此选项:使用最近浏览器中的用户代理字符串。
错误处理
如果http响应代码是
4nn
(客户端错误)或5nn
(服务器错误),则可能需要读取HttpURLConnection#getErrorStream()
查看服务器是否发送了任何有用的错误信息。如果http响应代码是-1,那么连接和响应处理出现了问题。这个
HttpURLConnection
在旧的JRE中实现在保持连接活动方面有些缺陷。您可以通过设置http.keepAlive
系统属性到false
. 您可以在应用程序开始时通过以下方式以编程方式执行此操作:上载文件
你通常会用
multipart/form-data
混合post内容(二进制和字符数据)的编码。编码在rfc2388中有更详细的描述。如果对方是
HttpServlet
,那么doPost()
方法,部件将由HttpServletRequest#getPart()
(注意,因此不是getParameter()
等等!)。这个getPart()
方法是相对较新的,它是在Servlet3.0(GlassFish3、Tomcat7等)中引入的。在Servlet3.0之前,最好的选择是使用ApacheCommonsFileUpload来解析multipart/form-data
请求。关于fileupload和servelt3.0方法的示例,请参见此答案。处理不受信任或配置错误的https站点
有时您需要连接https url,可能是因为您正在编写web scraper。在这种情况下,你可能会面临
javax.net.ssl.SSLException: Not trusted server certificate
在一些https站点上,没有更新ssl证书,或者java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
或者javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
在一些配置错误的https网站上。以下一次运行
static
web scraper类中的初始值设定项应该HttpsURLConnection
对那些https站点更加宽容,因此不再抛出那些异常。遗言
apache httpcomponents httpclient在这方面要方便得多:)
httpclient教程
httpclient示例
解析和提取html
如果您只想从html解析和提取数据,那么最好使用jsoup之类的html解析器
java中领先的html解析器的优缺点是什么
如何用java扫描和提取网页
6za6bjd06#
我也很受这个React的启发。
我经常在我需要做一些http的项目上,我可能不想引入很多第三方依赖项(引入其他依赖项等等)
我开始根据这段对话编写自己的实用程序(没有完成的地方):
然后就是一堆或静态方法。
然后发布。。。
好吧,你明白了。。。。
以下是测试:
qncylg1j7#
在使用http时,参考http几乎总是更有用的
HttpURLConnection
而不是基类URLConnection
(自URLConnection
是一个抽象类URLConnection.openConnection()
在一个http网址上,这是你无论如何都会得到的)。那你就不用依赖
URLConnection#setDoOutput(true)
隐式地将请求方法设置为post而不是dohttpURLConnection.setRequestMethod("POST")
有些人可能会觉得更自然(而且还允许您指定其他请求方法,如put、delete等)。它还提供了有用的http常量,因此您可以执行以下操作: