简介:在Android开发中,使用 HttpURLConnection
与.NET平台上的WebService进行交互是一种常见的需求。本文将介绍 HttpURLConnection
的基础知识,解释WebService的工作原理,并通过详细的步骤指导如何通过 HttpURLConnection
发起SOAP请求以调用.NET WebService。文章还将提供实际代码示例,并强调错误处理、资源管理和安全性等方面的注意事项。
1. HttpURLConnection简介和优势
1.1 HttpURLConnection简介
HttpURLConnection
是Java标准库中提供的用于发送HTTP请求和接收HTTP响应的类。它是一个基于RFC 2616标准实现的可扩展的HTTP客户端,能够进行基本的HTTP协议操作,如GET、POST等。它是网络编程中经常用到的类之一,广泛应用于与Web服务交互的场景中。
1.2 HttpURLConnection优势
相比于其他HTTP客户端库,如Apache的HttpClient和OkHttp, HttpURLConnection
的优势在于它作为Java标准库的一部分,无需额外添加依赖,开箱即用。它具有较强的跨平台性,并且能够很好地与Java的其他部分,例如输入输出流,安全机制等协同工作。由于其简洁性和可靠性,对于需要快速构建和部署HTTP服务的开发者来说, HttpURLConnection
是一个非常合适的选择。
2. WebService调用原理
2.1 WebService技术概述
2.1.1 WebService的定义和架构
WebService是一种Web应用,它允许应用程序通过Web发布、定位和调用远程服务。它基于标准化的通信协议,通常是HTTP,实现了系统之间不同编程语言和平台的透明互操作性。从架构上看,WebService主要由服务提供者(Service Provider)、服务请求者(Service Requester)和服务注册中心(Service Registry)组成。服务提供者负责发布服务,服务请求者通过网络发现并调用服务,而服务注册中心则用于存放服务的元数据,使得服务可以被发现。
2.1.2 WebService的优势和应用场景
WebService的一个核心优势在于它的松耦合特性,这意味着软件组件可以独立于其他组件进行开发和更新。此外,WebService可以利用现有的网络基础设施,支持跨平台和不同语言的通信。它的应用场景包括但不限于电子商务、集成企业应用程序、系统间的远程过程调用(RPC)等。例如,一个使用Java编写的前端应用程序可能需要与一个使用.NET开发的后端服务进行通信,WebService使得这种跨平台的通信成为可能。
2.2 WebService的交互模式
2.2.1 请求/响应模式
请求/响应模式是WebService中最基本的交互方式,它类似于日常生活中的查询和响应过程。服务请求者发送一个请求消息到服务提供者,然后等待并接收响应消息。这种模式是最常见的一种,适用于大多数需要服务提供者返回数据的场景。例如,一个天气查询服务,用户提交一个城市名称的查询请求,然后接收包含该城市当前天气状况的响应。
2.2.2 发布/订阅模式
发布/订阅模式是一种多对多的交互方式,其中一个服务发布信息供多个服务订阅者接收。这种模式通常用于信息共享、事件通知等场景。例如,股票交易系统可以发布实时的股票价格变动信息,而订阅者则可以是需要这些信息的其他应用程序或服务。
graph LR
A[发布者] -->|发布信息| M[消息队列]
B[订阅者] -->|订阅| M
C[订阅者] -->|订阅| M
M -->|通知| B
M -->|通知| C
上图展示了发布/订阅模式的一个简化的流程,其中发布者将信息推送到消息队列,而订阅者则从消息队列中拉取信息。
2.2.3 代码块示例:发送SOAP请求
// 创建URL对象
URL url = new URL("***");
// 打开连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法
connection.setRequestMethod("POST");
// 添加必要的请求头
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setRequestProperty("SOAPAction", "***");
// 发送POST请求必须设置如下两行
connection.setDoOutput(true);
connection.setDoInput(true);
// 获取输出流
OutputStream os = connection.getOutputStream();
// 发送请求到服务器
os.write(soapRequest.getBytes());
os.flush();
os.close();
在上述代码块中,我们创建了一个指向WebService的URL,并通过 HttpURLConnection
建立了连接。然后我们设置了请求方法为POST,并设置了必要的HTTP头信息,包括内容类型和SOAP动作。最后我们获取输出流并发送SOAP请求。
SOAP请求头的设置
在SOAP请求中,HTTP头的设置非常关键,它包含了关于消息的元数据信息。通过设置正确的HTTP头,可以确保请求被正确地路由和处理。例如,"Content-Type"指定了消息内容的类型,而"SOAPAction"则指定了SOAP消息的行动。
SOAP消息体的构建
SOAP消息体是实际包含请求数据的地方。构建SOAP消息体通常涉及到创建一个XML格式的字符串,这个字符串定义了消息的结构和包含的数据。该消息被序列化后写入到HTTP请求的输出流中,从而发送到远程服务。正确构建SOAP消息体是确保远程服务理解并正确处理请求的关键。
通过深入理解这些基础组件和如何将它们组合起来,开发者可以有效地利用WebService进行服务的发现、调用和交互,进而实现高效、跨平台的系统集成。在下一节中,我们将详细探讨如何构建SOAP请求,以及如何通过HttpURLConnection发送这些请求。
3. WebService的SOAP请求格式
3.1 SOAP协议简介
3.1.1 SOAP协议的工作原理
SOAP(Simple Object Access Protocol)是一种基于XML的消息传递协议,用于在网络上的应用程序之间交换信息。SOAP的出现主要是为了提供一个简单的、轻量级的机制来实现跨平台的分布式计算环境。其工作原理主要基于以下几个步骤:
- 消息创建 :客户端创建一个SOAP消息,通常包含一个请求的描述,并将其封装在HTTP请求中发送出去。
- 消息传输 :SOAP消息通过HTTP协议传输至服务器端。
- 消息解析 :服务器端解析HTTP包中的SOAP消息,并根据消息内容执行相应的处理。
- 响应生成 :服务器根据处理结果生成响应消息,并将该SOAP消息封装在HTTP响应中送回客户端。
- 响应解析 :客户端解析从服务器收到的SOAP响应消息,提取数据或状态信息。
SOAP消息具有自描述特性,这意味着消息体包含了描述消息格式和处理所需的所有信息。SOAP协议是Web服务技术的基础之一,它不依赖于传输协议,但在实际应用中,SOAP通常使用HTTP协议作为底层传输机制。
3.1.2 SOAP消息结构
SOAP消息的结构是一个严格的XML格式,主要包括以下几个部分:
- Envelope :SOAP消息的根元素,它将整个SOAP消息定义为一个单元。任何SOAP消息都必须包含一个Envelope元素。
- Header :(可选)包含了一个或多个Header条目,每个条目包含了一组信息,如认证数据、事务信息等。这些信息对于消息的处理可能有用,但不是必需的。
- Body :包含了实际的请求或响应信息。每个SOAP消息必须包含一个Body元素。
- Fault :(可选)当SOAP消息处理中出现错误时,可以在Body元素内包含一个Fault元素,提供错误信息。
3.2 构建SOAP请求
3.2.1 HTTP头的设置
构建SOAP请求时,HTTP头信息的设置是重要的一环。HTTP头信息会告诉服务器端如何处理请求,常见的HTTP头设置包括内容类型(Content-Type)和内容长度(Content-Length)等。
以Java中的 HttpURLConnection
为例,下面是设置HTTP头的代码示例:
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法为POST
connection.setRequestMethod("POST");
// 设置允许输入输出
connection.setDoInput(true);
connection.setDoOutput(true);
// 设置内容类型为SOAP
connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
// 设置SOAPAction,这是一个HTTP头,指定SOAP请求所要调用的服务方法
connection.setRequestProperty("SOAPAction", "***");
3.2.2 SOAP消息体的构建
SOAP消息体是实际发送给服务器的数据部分。构建SOAP消息体通常需要手动编写XML格式的内容,或者使用一些现成的库来生成。下面是一个简单的SOAP消息体构建的例子:
<soap:Envelope xmlns:soap="***"
xmlns:web="***">
<soap:Header/>
<soap:Body>
<web:SayHello>
<web:name>John</web:name>
</web:SayHello>
</soap:Body>
</soap:Envelope>
在Java代码中,你可以使用字符串拼接的方式创建一个SOAP消息体,或者使用XML处理库如 JDOM
或 DOM4J
来构建更加复杂的XML结构。之后,你需要将这个消息体通过 HttpURLConnection
输出流发送出去。
String soapMessage = ...
OutputStream out = connection.getOutputStream();
out.write(soapMessage.getBytes());
out.flush();
构建SOAP请求需要对XML和HTTP协议有一定的了解,同时确保SOAP消息格式正确和符合服务器端的要求。服务器端接收到SOAP请求后,会解析消息体内容并根据定义好的服务接口进行处理。
4. HttpURLConnection的使用步骤和代码示例
4.1 HttpURLConnection的初始化
4.1.1 创建HttpURLConnection对象
为了开始使用HttpURLConnection,首先我们需要创建一个HttpURLConnection实例。通常,这是通过打开一个URL对象,然后调用其 openConnection
方法来完成的。这个方法返回一个URLConnection对象,而我们通常将它强制转换为HttpURLConnection对象。
以下是如何创建HttpURLConnection对象的示例代码:
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
4.1.2 设置请求方法和URL
创建了HttpURLConnection实例后,接下来我们需要设置请求方法,如GET或POST。此外,我们还可以设置一些基本的请求属性,比如连接超时时间、读取超时时间以及是否允许自动重定向。
示例代码如下:
// 设置请求方法为GET
connection.setRequestMethod("GET");
// 设置连接超时时间为5秒
connection.setConnectTimeout(5000);
// 设置读取超时时间为10秒
connection.setReadTimeout(10000);
// 允许自动重定向
connection.setInstanceFollowRedirects(true);
4.2 HttpURLConnection的配置
4.2.1 配置请求头
请求头是HTTP请求的一部分,用于传达有关请求的额外信息。在使用HttpURLConnection时,我们可以通过 setRequestProperty
方法来设置请求头。
例如,如果我们需要添加一个用户代理头,可以这样做:
// 添加用户代理头
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MyBot/1.0)");
4.2.2 设置请求参数
对于GET请求,请求参数通常附加在URL的查询字符串中。而对于POST请求,这些参数会在请求体中发送。在Java中,我们可以使用 OutputStreamWriter
来写入请求体。
示例代码如下:
// 对于POST请求,我们需要设置请求体内容类型
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 获取请求体的输出流
OutputStream os = connection.getOutputStream();
Writer writer = new OutputStreamWriter(os, "UTF-8");
writer.write("param1=value1¶m2=value2");
writer.flush();
writer.close();
4.3 HttpURLConnection代码示例
4.3.1 发送GET请求的代码示例
以下是使用HttpURLConnection发送GET请求的完整代码示例:
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法为GET
connection.setRequestMethod("GET");
// 设置连接超时和读取超时
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
// 允许自动重定向
connection.setInstanceFollowRedirects(true);
// 打开连接并读取响应
connection.connect();
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
in.close();
// 打印响应内容
System.out.println(response.toString());
4.3.2 发送POST请求的代码示例
以下是使用HttpURLConnection发送POST请求的完整代码示例:
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法为POST
connection.setRequestMethod("POST");
// 设置连接超时和读取超时
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
// 设置必要的请求头
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 获取请求体的输出流并写入数据
OutputStream os = connection.getOutputStream();
Writer writer = new OutputStreamWriter(os, "UTF-8");
writer.write("param1=value1¶m2=value2");
writer.flush();
writer.close();
// 打开连接并读取响应
connection.connect();
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
in.close();
// 打印响应内容
System.out.println(response.toString());
在发送POST请求时,我们通常需要准备要发送的数据,这可以通过将参数拼接到一个字符串中来实现。然后,我们将这个字符串写入到连接的输出流中。注意,关闭输出流是必须的,以便发送数据并告诉服务器我们已经完成数据的发送。
接下来的章节中,我们将进一步讨论如何建立连接、发送数据以及如何从服务器接收和处理响应数据。
5. 连接建立和数据发送
5.1 连接的建立
5.1.1 连接的建立过程
在使用HttpURLConnection时,连接的建立涉及到几个关键步骤。首先,通过调用URL对象的 openConnection()
方法获取一个连接对象。随后,将这个连接对象转换为HttpURLConnection类型,以便进行进一步的配置和操作。
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
接下来,配置连接的相关参数,例如请求方法(GET、POST等)、超时时间以及需要发送的请求头信息:
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
完成上述配置后,调用 connect()
方法实际建立连接。
connection.connect();
5.1.2 网络异常处理
在建立连接的过程中,可能会抛出多种异常,比如 MalformedURLException
、 IOException
等。因此,使用try-catch结构来捕获这些异常是必要的,以确保程序的健壮性。
try {
connection.connect();
} catch (IOException e) {
// 处理网络异常,例如连接失败、读取超时等
e.printStackTrace();
}
5.2 数据的发送
5.2.1 发送数据的过程
一旦连接建立,就可以开始发送数据。对于POST请求,通常需要在连接建立后设置请求体,并使用 OutputStream
进行数据的发送。
connection.setDoOutput(true); // 允许输出
try (OutputStream os = connection.getOutputStream()) {
// 发送的数据需要转换为字节流
byte[] input = "some data".getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
5.2.2 数据发送的优化方法
发送数据时,应注意几个优化点:
- 合理设置缓存区大小 :避免过大的缓存导致内存占用过高,同时,过小的缓存会增加网络交互次数。
- 流式发送数据 :大数据量时,可以边读取边发送,减少内存占用。
- 关闭自动重定向 :有时服务器的自动重定向可能会导致不必要的网络开销,可以通过设置
setInstanceFollowRedirects(false)
来关闭自动重定向。
connection.setInstanceFollowRedirects(false);
- 异步发送数据 :在支持多线程的环境中,可以考虑使用异步方式发送数据,减少阻塞时间。
通过上述步骤,我们可以完成HttpURLConnection的初始化、配置以及数据的发送,并且在过程中考虑了异常处理和优化方法,以确保数据传输过程既稳定又高效。
6. 响应读取和数据处理
6.1 响应的读取
6.1.1 读取响应的过程
在使用HttpURLConnection类与WebService进行交互的过程中,读取服务器响应是一个至关重要的步骤。这个过程通常涉及以下几个关键点:
-
连接服务器 - 首先,确保已经建立了连接。这通常是通过调用
HttpURLConnection.getInputStream()
方法来完成的,该方法会返回一个InputStream
实例,用于从服务器读取响应数据。 -
读取输入流 - 接下来,从返回的输入流中读取数据。这通常是通过使用
InputStreamReader
将字节流转换为字符流,并使用BufferedReader
来逐行读取响应内容。 -
处理数据 - 读取到的响应数据需要被适当地处理,这可能包括字符编码转换、格式解析等。
-
关闭流 - 在读取完数据后,必须确保释放资源。这通过调用输入流的
close()
方法实现。
以下是使用Java代码读取HTTP响应的基本步骤:
// 假设urlConnection是已经配置好的HttpURLConnection对象
BufferedReader reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line).append("\n");
}
reader.close();
// 输出响应内容
System.out.println(response.toString());
6.1.2 字符编码和乱码处理
在网络编程中,字符编码是一个常被提及的问题。不同服务器可能会使用不同的字符集来编码响应数据,因此在读取响应时可能会遇到乱码问题。为了解决这个问题,应该在读取输入流之前正确地设置字符编码。
通常,服务器响应头中的 Content-Type
字段会指示响应的内容类型,其中可以包含字符编码信息。例如:
Content-Type: text/xml; charset=utf-8
开发者可以根据这个字段来设置字符编码。以下是如何在读取响应之前设置字符编码的示例:
if (urlConnection.getContentEncoding() != null) {
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),
urlConnection.getContentEncoding()));
} else {
// 如果响应头中没有指定字符编码,可以根据实际情况指定默认编码
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));
}
6.2 数据的解析和处理
6.2.1 使用XML解析器解析SOAP响应
SOAP响应本质上是一个XML格式的字符串,因此可以使用XML解析器来解析这些响应内容。常见的XML解析库包括 javax.xml.parsers
、 org.jdom
、 org.w3c.dom
等。在Java中,通常使用 DocumentBuilder
来解析XML文档。
以下是使用 DocumentBuilder
解析SOAP响应的一个基本示例:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(response.toString())));
// 获取指定元素,例如获取第一个<fault>元素
NodeList faultNodes = document.getElementsByTagName("fault");
Element faultElement = (Element) faultNodes.item(0);
6.2.2 JSON数据的解析和处理
随着RESTful API的流行,JSON数据格式也变得越来越常见。在Java中,处理JSON数据时可以使用 org.json
库、 com.fasterxml.jackson.databind
或者 com.google.gson
等库。
以下是一个使用Gson库来解析JSON响应的示例:
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> jsonResponse = gson.fromJson(response.toString(), type);
System.out.println(jsonResponse);
在处理JSON数据时,应当注意JSON的结构和字段,以正确地从响应中提取需要的信息。此外,异常处理也是必要的,因为JSON格式错误或解析问题都可能引发异常。
总结第六章的内容,我们介绍了如何从HttpURLConnection读取响应,并处理了字符编码的常见问题。我们还讨论了使用XML和JSON解析器来解析SOAP和RESTful API的响应数据。通过这些知识点,我们可以更好地处理从WebService交互中得到的复杂数据。
7. 异常处理和资源管理
在开发过程中,异常处理和资源管理是保证程序稳定性和健壮性的关键部分。特别是对于使用HttpURLConnection进行网络通信的应用程序,有效地处理各种可能发生的异常情况,以及确保网络资源被正确管理,是提高应用性能和用户体验的重要方面。
7.1 异常处理
7.1.1 常见异常及处理策略
在使用HttpURLConnection时,我们可能会遇到多种异常,比如 IOException
、 ConnectException
等。合理地捕获和处理这些异常,能帮助我们诊断问题并给出恰当的用户反馈。
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
try {
URL url = new URL("***");
urlConnection = (HttpURLConnection) url.openConnection();
// 发送请求、读取响应等操作...
} catch (MalformedURLException e) {
// 处理URL错误异常
System.err.println("Malformed URL: " + e.getMessage());
} catch (IOException e) {
// 处理其他网络相关的异常
System.err.println("Network error: " + e.getMessage());
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// 可以记录日志
}
}
}
7.1.2 异常捕获和日志记录
在实际开发中,除了基本的异常捕获,我们还需要对异常进行记录,以便于后续的问题排查和复现。通常会使用日志框架,如Log4j或者SLF4J,来实现这一功能。
try {
// 网络请求和数据处理代码
} catch (Exception e) {
// 使用日志框架记录异常信息
Log.error("An error occurred during the network request", e);
// 可以根据需要记录堆栈跟踪等信息
}
7.2 资源管理
7.2.1 使用try-catch-finally确保资源释放
在Java中,资源如文件流或网络连接,需要被显式关闭,以防内存泄漏和资源占用。使用try-catch-finally结构是一种保证资源释放的可靠方法。
BufferedReader reader = null;
try {
URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 初始化连接、发送请求等
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// 读取响应数据
} catch (IOException e) {
// 异常处理
Log.error("Error while opening connection", e);
} finally {
// 释放资源
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
Log.error("Error while closing reader", e);
}
}
}
7.2.2 使用AutoCloseable管理资源
从Java 7开始,引入了try-with-resources语句,它可以自动管理实现了AutoCloseable接口的资源,从而简化代码并避免资源泄露。
try (URL url = new URL("***");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
// 使用reader对象读取数据
} catch (IOException e) {
// 异常处理
Log.error("Error while processing the request", e);
}
try-with-resources结构保证了所有资源在try代码块执行完毕后自动关闭,无论是正常执行还是发生异常,都无需手动关闭资源,使代码更简洁且安全。
在这一章节中,我们了解了异常处理的重要性和使用try-catch-finally进行资源管理的传统方法,以及try-with-resources带来的便利。对于使用HttpURLConnection的开发者来说,掌握这些知识,能显著提高代码的质量和应用的稳定性。
简介:在Android开发中,使用 HttpURLConnection
与.NET平台上的WebService进行交互是一种常见的需求。本文将介绍 HttpURLConnection
的基础知识,解释WebService的工作原理,并通过详细的步骤指导如何通过 HttpURLConnection
发起SOAP请求以调用.NET WebService。文章还将提供实际代码示例,并强调错误处理、资源管理和安全性等方面的注意事项。