httpcomponentClient upload file

本文详细介绍了如何使用HttpComponents解决与各种问题跟踪器(如JIRA、Bugzilla等)集成时遇到的文件上传问题。包括从旧版本CommonsHttpClient升级到新版本HttpComponents的体验、API使用技巧及解决上传失败的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://radomirml.com/2009/02/13/file-upload-with-httpcomponents-successor-of-commons-httpclient




File upload with HttpComponents Client 4.0 (successor of Commons HttpClient 3.x)

by radomir on February 13, 2009

Background: I’m working on an application that should be able to integrate with various issue trackers (JIRA, Bugzilla, etc.) First I tried using the latest stable branch of Apache Commons HttpClient 3.1 but soon faced problems as JIRA (running on Tomcat) was not able to extract all parameters I was sending with “multipart/form-data” encoding. I’ve found similar problems reports on the Internet but no solution. So, I’ve decided to try the latest HttpComponents Client (4.0-beta2, while core library was 4.0-beta3 at the time of writing) which came with new problems but my form submission and file upload worked at the end. I summarize my experience here.

As soon as I downloaded HttpComponents Client I realized why they changed the name from Commons HttpClient. This is a completely new API! If you already have code that relies on Commons HttpClient you can not easily switch jar file and make some minor changes. Fortunatelly, HttpComponents use different packages so you should be able to keep your HttpClient code and have both versions coexist in the same application without conflicts. However, I can’t resist to mention that HttpComponents API looks to me a bit over-engineered and so low level that it hurts. (But maybe it’s just me being spoiled after a month on Groovy.)

HttpComponents Client still doesn’t have an appropriate documentation and I could not find a single example of file upload that worked for me. So, after mingling my existing code and code from HttpComponents test cases, I’ve finally made a first version that was able to upload file and here’s somewhat simplified version of it:

public void testUpload() throws Exception {
	HttpClient httpclient = new DefaultHttpClient();
	HttpPost httppost = new HttpPost(myUploadUrl);

	MultipartEntity reqEntity = new MultipartEntity(
		HttpMultipartMode.BROWSER_COMPATIBLE);

	reqEntity.addPart("string_field",
		new StringBody("field value"));

	FileBody bin = new FileBody(
		new File("/foo/bar/test.png"));
	reqEntity.addPart("attachment_field", bin );

	httppost.setEntity(reqEntity);

	System.out.println("executing request " + httppost.getRequestLine());
	HttpResponse response = httpclient.execute(httppost);
	HttpEntity resEntity = response.getEntity();

	if (resEntity != null) {
		String page = EntityUtils.toString(resEntity);
		System.out.println("PAGE :" + page);
	}
}

I omit package imports in the example above but I’m sure you’ll manage without it. Notice use of HttpMultipartMode.BROWSER_COMPATIBLE parameter in line 6. It was crucial for me as upload didn’t work when I used default constructor for MultipartEntity (that initializes entity for the strict multipart mode). With hope that code above is all what’s needed, I made a small change (replacing lines 11-13 above) to upload image from byte array instead from file:

	reqEntity.addPart("attachment_field",
		new InputStreamBody(
			new ByteArrayInputStream(imageBytes),
			"image/png", "test.png"));

Surprisingly, this change broke my upload! Again, documentation and googling on this topic didn’t give me any clue on what could be wrong. So, I plunged into HttpComponents source code and found that the major different between the InputStreamBody and FileBody was that method getContentLength() of the former was returning -1 (which is somewhat logical but again…). As I already had image as a byte array, content length was known to me. So, I extended InputStreamBody class as follows:

class InputStreamKnownSizeBody extends InputStreamBody {
	private int lenght;

	public InputStreamKnownSizeBody(
			final InputStream in, final int lenght,
			final String mimeType, final String filename) {
		super(in, mimeType, filename);
		this.lenght = lenght;
	}

	@Override
	public long getContentLength() {
		return this.lenght;
	}
}

Now I could use my InputStreamKnownSizeBody class to upload any in-memory file:

	reqEntity.addPart("attachment_field",
		new InputStreamKnownSizeBody(
			new ByteArrayInputStream(imageBytes),
			imageBytes.length, "image/png", "test.png"));

At the end, although I’m not delighted with complexities of HttpComponents, it worked for me at the end and I resolved file upload issues I experienced with Commons HttpClient. I hope this post will be of help to someone.

EDIT (2010-10-20): At least few people were struggling with requirement for the MIME library (see bellow discussion). I’ve personally switched to the 4.1 Alpha 2 (the latest version at the time of writing) which removes dependency on org.apache.james.mime4j and comes with own httpmime-4.1-xxx.jar library.



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值