`

Java httpclient解决方案中的中文传递

阅读更多

1 Commons HttpClient 开源项目简介 Http 协议是一种应用十分广泛的网络应用层协议。在Java 网络编程中我们会经常碰到Http 协议编程, 虽然JDK 提供了 HttpURLConnection 编程接口对Http 协议进行支持, 但是由于协议应用本身的复杂性, 使得在大量实际项目单纯使用JDK 进行Http编程仍然相对比较困难。针对这种情况, 开源软件组织Apach 推出了HttpClient 开源组件, 并且提供稳定持续的升级版本, 因此在实际项目中采用HttpClient 组件进行Http 协议编程是一种高效经济的解决方案。

2 Commons HttpClient 中文环境下编程常见问题由于HttpClient 组件设计的高度灵活性及易用性, 应用HttpClient 组件进行编程本身并不复杂。但是由于Java 编程环境自身容易出现字符编码问题, 衍生于Java 语言并主要由英语语系国家技术人员推出的HttpClient 组件自然在中文环境中会存在一定的编码问题, 同时由于部分Web 浏览器及Web 服务器并未严格实现标准Http 协议规范, 使得比较严格遵循标准Http 协议规范的Http-Client 组件在与部分浏览器及服务器进行交互时会出现少量兼容性问题。笔者在中文环境下用HttpClinet 开发校外资源访问系统的过程中碰到系列HttpClient 技术问题, 经过测试查证找到相应的解决办法, 这对解决HttpClient 编程问题, 特别是中文环境下Http-Client 编程具有较大的借鉴作用。( 注: 本文编程的HttpClient 组件版本为: Release 3.1 Beta 1)

 

3 Commons HttpClient 编程的典型问题及解决办法

3.1 URL 中文参数无法识别的问题通常情况在Commons HttpClient 编程中我们用下列语句就可以向一个目标服务器提交一个Web 请求: HttpClient client=new HttpClient(); GetMethod method = new GetMethod (url);//本示例使用Get 方法, 当然也可使用Post 方法PostMethod method//=new PostMethod(url); client.executeMethod(method); InputStream receiver=method.getResponseBodyAsStream(); 如果URL 没有中文参数,以上语句执行起来没有任何问题,但是如果URL 中含有中文字符,中文参数将无法被Web 服务器识别, 程序虽然可以正常运行, 但却无法得到正确结果。同时返回的Http 响应头, 如果含有中文字符也将出现乱码。分析源码发现, 这是HttpClient 中的HttpElementCharset 参数( 创建HTTP headers 的字符集) 的默认值为US- ASCII, ContentCharset 参数( 创建contentbody 的字符集) 的默认值为ISO- 8859- 1 的原故, 因此需要使用下列语句改变这些参数的默认值: client = new HttpClient(); params=client.getParams(); params.setHttpElementCharset("GBK"); params.setContentCharset("GBK"); 或者使用: method.getParams().setHttpElementCharset("GBK"); method.getParams().setCredentialCharset("GBK"); method.getParams().setContentCharset("GBK"); 第一种方式可能会更好, 它在HttpClient 初始化时就对字符默认参数进行了设置, 作用范围更广。第二种方式仅对使用具体的请求方法时起作用, 字符集的作用范围有限。一般情况下我们用上述语句即可实现中文字符的正确识别。但要深入使用我们会发现如果URL 中文参数含有中文特殊字符(如“{”, “}”等符号), 程序将抛出URIException 异常,导致请求无法完成。继续研究HttpClient的源代码发现, URI 类是负责解析URL 的核心类, 控制URL 编码字符集是ProtocolCharset 参数, 默认情况下为UTF- 8 编码, 同时还在URI 的构造函数提供了一个逻辑值来决定是否过滤非法字符, 而恰恰一些中文特殊字符也被当成非法的字符过滤掉了, 根据产生问题的原因, 我们在基本解决中文编码问题的基础上结合以下容错的方法来最终保证中文编码的正确识别: String url=⋯.; try {strUri=new URI(uri,true,"GBK");} catch(URIException e) {strUri=new URI(uri,false,"GBK");} method.setURI(strUri); 经测试上述办法解决大量的已知URL 中文参数不能识别的问题, 当然如果在程序个别地方上述方法依然不能奏效, 你还可以使用Java 中文编码转换的基础解决方法, 借助ISO- 8859- 1 标准编码过渡, 能够轻易将JVM在网络传送过程转换成的UTF8 编码还原成GBK 编码, 下面的代码实现了这一功能: byte [] b; String utf8_value; utf8_value = request.getParameter("NAME");//从HTTP 流中取"NAME"的UTF8 数据 b = utf8_value.getBytes("8859_1"); //中间用ISO- 8859- 1 过渡 String name = new String(b, "GB2312"); //转换成GB2312 字符

3.2 URL 中的%问题部分不太规范的中文网站中使用%作URL 中参数的一部分传递给服务器, 而中文Windows 中的许多主流浏览器也兼容这一例外。事实上%是作为Http 协议中的UrlEncode 编码的保留字符不能直接在URL 中使用, 必须被转义成%25 这样的形式, 事实上HttpClient 就会自动将字符%转化成%25。正是这种原因当HttpClient 截获IE 浏览器的请求并将其转发到服务器时, 将会导致查询参数错误。分析HttpClient 的源码发现, 这一转化是在URI 类中实现的, 经反复测试未能找到一种通过HttpClient 公开接口实现这一兼容性的方法。目前只能采取修改URI 类源码重新编译的办法来实现: public static final BitSet allowed_query = new BitSet(256); // Static initializer for allowed_query static { allowed_query.or(uric); allowed_query.clear('%');将源码中此语句去掉或注释即可}

3.3 Cookie 整合问题 IE 和Firefox 在发送请求给服务器时会把所有的cookie 打包成一个, 然后在这个cookie 里按照分号把每一项隔开, 中间有个空格。但httpclient 会在header 里构建多个cookie 项, 每一项只含有一个cookie, 这同IE 是不一样的。为了使用IE 这种发送方式, 我们需要设置一个请求方法中的一个Cookie 参数, 参考设置如下:method.getParams().setParameter(HttpMethodParams.SINGLE_COOKIE_HEADER,new Boolean(true)); //使多个cookie 合并成一个cookie 头

3.4 chunked 编码不规范的问题有时候Web 服务器生成HTTP Response 是无法在Header 就确定消息大小的, 这时一般来说服务器将不会提供Content- Length 的头信息, 而采用Chunked 编码动态的提供body 内容的长度。Chunked 编码使用若干个Chunk 串连而成, 由一个标明长度为0 的chunk 标示结束。使用十分广泛的Tomcat Web 服务器大量采用了Chunked 编码方案, 然而早期的Tomcat Web 服务器实现并不十分规范, 并没有以标明长度为0 的chunk 标示内容传输结束。因此HttpClient 在接收这些早期的Tomcat Web 服务器的Http 响就会导致解析错误。分析HttpClient 源码发现, ChunkedInputStream 类负责在HttpClient 中解析chunked 编码, 修改一个此类中getChunk-SizeFromInputStream(final InputStream in)方法, 可使标准的和上述非标准的chunked 编码均可正常解析。具体修改方法如下: private static int getChunkSizeFromInputStream(final InputStream in) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); // States: 0=normal, 1=\r was scanned, 2=inside quoted string, - 1=end int state = 0; while (state ! = - 1) { int b = in.read(); if (b == - 1) { return 0;//新增加语句 throw new IOException("chunked stream ended unexpectedly");//原始语句, 需将其去掉或注释掉}

3.5 Host 头无法修改的问题 HttpClient 本身在HttpMethodBase 类中提供增加和修改Http 请求头的addRequestHeader 和setRequestHeader 方法, 然而却无法修改Host 参数, 而在一此特殊的场合又要求修改这一参数。经分析源码发现, HttpClient 在设置Http 请求头设计成了不能修改的固定模式。因此为适应特殊要求, 只能修改和重编译HttpMethodBase 类。具体修改方法如下: protected void addRequestHeaders(HttpState state, HttpConnection conn) throws IOException, HttpException { LOG.trace("enter HttpMethodBase.addRequestHeaders(HttpState, " + "HttpConnection)");

分享到:
评论

相关推荐

    httpclient4.0源文件

    在实际开发中,我们可以利用HttpClient 4.0的灵活性来构建各种网络通信解决方案,例如: 1. **发送GET和POST请求**:通过构建`HttpGet`和`HttpPost`对象,设置URL和参数,然后使用HttpClient执行。 2. **处理响应*...

    httpclient Demo 案例 含jar

    通过这个案例,我们不仅学习了HttpClient的基本用法,还了解了如何针对特定问题定制解决方案。HttpClient的灵活性和强大功能使其成为Java开发者处理HTTP通信的首选工具之一。在实践中,深入理解HttpClient的工作原理...

    commons-httpclient-3.1.jar_C++_

    尽管这提供了一种可能的解决方案,但在实际应用中,开发者需要权衡额外的复杂性和性能损失,可能需要考虑其他更适合C++的HTTP客户端库。在选择合适的技术路线时,应综合考虑项目的具体需求、开发效率和性能指标。

    httpclient 4.5 api文档

    - **解决方案**:使用预检查条件(If-Match, If-Unmodified-Since等)。 **1.5.3 自动异常恢复** - **定义**:在发生某些类型的异常时,自动尝试重新执行请求。 - **机制**:RequestRetryHandler接口。 **1.5.4 ...

    httpClient4.1入门教程.docx

    HttpClient 的灵活性和强大功能使其成为 Java 开发者处理 HTTP 任务的首选工具,无论是简单的网页抓取还是复杂的 Web 服务交互,HttpClient 都能提供稳定和高效的解决方案。随着 HTTP 协议的发展,HttpClient 也在...

    HttpClient以及获取页面内容应用

    8. 便携可靠的套接字工厂使它更容易的使用第三方解决方案。 9. 连接管理器支持多线程应用。支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接。 10. 自动处理Set-Cookie中的Cookie。 11....

    Feign发送Get请求时,采用POJO对象传递参数的最终解决方案.docx

    ### Feign发送Get请求时,采用POJO对象传递参数的最终解决方案 #### 前言 在Spring Cloud技术栈中,Feign作为一种声明式的HTTP客户端框架,极大地简化了微服务间的HTTP请求调用过程,使其几乎如同调用本地方法一般...

    Web Services应用实例 -- Java Web App远程调用SAS程序的解决方案

    在本实例中,我们将探讨如何使用Java Web应用程序远程调用SAS程序,这涉及到Web服务技术与统计分析软件SAS的集成。以下是相关知识点的详细说明: 1. **Web服务**: Web服务是通过HTTP协议传输数据的服务,它使用...

    java大文件分块上传断点续传demo

    本Java Demo就是针对这个问题提供的一种解决方案,它允许开发者将大文件分成多个小块进行上传,并且支持在上传过程中因故中断后从上次断点继续上传,避免了重复传输已成功上传的数据。 首先,我们需要理解分块上传...

    java访问.net webservice获取与设置cookie

    在IT行业中,跨平台通信是常见的需求,Java和.NET之间的交互也不例外。本篇文章将深入探讨如何使用Java访问.NET Web服务,并在过程中获取和设置Cookie,以便...了解这些机制有助于构建可靠、健壮的跨平台通信解决方案。

    Java开发之微信二维码系统

    在本文中,我们将深入探讨如何使用Java开发微信二维码系统,这是一个功能完备的解决方案,可以直接导入并使用。微信二维码系统在现代移动应用中扮演着至关重要的角色,它为用户提供了便捷的登录、分享和支付功能。...

    java上传图片完整deom

    这个"java上传图片完整deom"示例提供了一个简单的解决方案,它包含了一整套用于实现图片上传功能的代码。下面,我们将深入探讨这个示例中涉及的关键知识点。 1. **文件I/O操作**:在Java中,上传图片首先需要读取...

    Java版极验验证Demo

    Java版的极验验证Demo是基于Java开发语言,主要用于后端服务器进行用户行为验证的一种解决方案。极验验证(Geetest)是一种智能验证码服务,旨在通过机器学习和行为分析技术,来区分真实用户与机器人,从而保护网站...

    java财付通支付接口源码实例

    通过Java来接入财付通支付网关,可以为您的业务提供安全、便捷的支付解决方案。 首先,我们来看"java财付通支付接口源码实例"这个项目的核心内容。这个实例是一个完整的Java Web工程,包含了实现财付通支付功能所需...

    分布式JAVA应用 基础与实践

    3. JMS(Java Message Service):Java消息服务,用于在分布式系统中传递异步消息,实现解耦和异步处理。 二、Java网络编程 1. Socket编程:Java的Socket类提供了基于TCP/IP的网络通信能力,可用于创建可靠的、双向...

    Java典型应用彻查1000例第二卷:网络应用开发(源码+PPT+习题).rar

    这本书不仅提供了理论知识,还通过实例深入解析了实际开发中的常见问题和解决方案,对于初学者和有经验的开发者来说都是极好的参考资料。 首先,Java在网络应用开发中的基础是Socket编程。Java Socket API提供了低...

    Java网络编程与分布式计算

    6. 分布式数据库:例如Cassandra、MongoDB和HBase等,它们提供跨多台机器的分布式数据存储解决方案。 7. Spring Cloud和Dubbo:这两者都是流行的微服务框架,帮助开发者构建、配置和管理分布式系统。 总结起来,...

    Java操作FastDFS

    Java操作FastDFS是一种常见的文件存储解决方案,特别是在分布式系统中。FastDFS是一个开源的高性能、轻量级的分布式文件系统,它对文件进行管理,包括文件存储、文件同步、文件访问(文件上传、文件下载)等功能,...

    Android高级应用源码-通过httpclient获取到JSON数据,展示到ListView.zip

    10. **本源码使用帮助.txt**:这个文件可能是提供给开发者的一份简短指南,解释了如何导入和运行代码,以及可能遇到的问题和解决方案。 通过这个源码,开发者可以学习到如何在Android应用中实现网络通信、JSON解析...

    双向HTTPS解决方案.zip

    6. **HTTPS连接**:在HTTP客户端(如Apache HttpClient或Java内置的HttpURLConnection)中,设置SSLSocketFactory,然后建立到服务器的连接。对于自定义的HTTP客户端,可能需要重写握手过程以处理自签名证书。 7. *...

Global site tag (gtag.js) - Google Analytics