第一次使用在使用豆瓣广播api(shuo/v2/statuses/)即碰壁,查找原因后发现最后的“/”必不可少。
那么我们继续:
MultiThreadedHttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager(); HttpClient client = new HttpClient(httpConnectionManager); PostMethod postMethod = new PostMethod("https://api.douban.com/shuo/v2/statuses/"); Part[] parts = new Part[2]; parts[0] = new StringPart("source","XXXXXXXXX", "UTF-8"); parts[0] = new StringPart("text", "ttttt", "UTF-8"); File file = new File("D:\\upload.jpg"); FilePart filePart = new FilePart("image", file.getName(), file,new MimetypesFileTypeMap().getContentType(file), "UTF-8"); parts[1] = filePart; MultipartRequestEntity requestEntity = new MultipartRequestEntity(parts, postMethod.getParams()); postMethod.setRequestEntity(requestEntity); postMethod.setRequestHeader("Authorization", "Bearer XXXXXX"); int statusCode = client.executeMethod(postMethod); String response = new String(postMethod.getResponseBody(), "UTF-8"); System.out.println("response--->" + response); System.out.println("statusCode--->" + statusCode);
我用的是httpclient3.1,返回结果为{"msg":"不支持的图片格式","r":0}
怎么办?检查多次代码,尝试调整编码多次后,依旧,宣告失败,上豆瓣api小组上搜索,满眼尽是提问的,官方的回复也很简单:"我们的api没问题,请检查参数Content-Type"。
好吧我怕你了,既然你说你们的api没问题,我拿你们提供的sdk参考下总可以吧。于是 下载sdk,我x,老版本的。attachments方式的,不支持image参数。
灵光一显,没准豆瓣自己官方的android里可以用一定的借鉴意义,反编译之,上 应用汇下载豆瓣广播,使用 apk2java解压,jdgui反编译之。
发现android客户端里使用的是httpclient4。参数设置可我也没什么不同。
使用httpclient4写了一个demo,果然可以发送成功。
public static void main(String[] args) throws FileNotFoundException, IOException { MultipartEntity localMultipartEntity = new MultipartEntity(); localMultipartEntity.addPart("text", new StringBody("texttexttext", Charset.forName("UTF-8"))); File file = new File("D:\\upload.jpg"); localMultipartEntity.addPart("image", new ByteArrayBody(IOUtils.toByteArray(new FileInputStream(file)), "image/jpeg", "upload.jpg")); HttpClient httpClient = new DefaultHttpClient(); HttpParams params = httpClient.getParams(); // 计算网络超时用 HttpConnectionParams.setConnectionTimeout(params, 5 * 1000); HttpConnectionParams.setSoTimeout(params, 2 * 1000); HttpPost request = new HttpPost("http://api.douban.com/shuo/v2/statuses/"); request.addHeader("Authorization", "Bearer XXXXXX"); request.setEntity(localMultipartEntity); HttpResponse response = httpClient.execute(request); System.out.println(response.getStatusLine()); response.getEntity().writeTo(System.out); } static class ByteArrayBody extends AbstractContentBody { private final byte[] data; private final String filename; public ByteArrayBody(byte[] paramArrayOfByte, String paramString) { this(paramArrayOfByte, "application/octet-stream", paramString); } public ByteArrayBody(byte[] paramArrayOfByte, String paramString1, String paramString2) { super(paramString1); if (paramArrayOfByte == null) throw new IllegalArgumentException("byte[] may not be null"); this.data = paramArrayOfByte; this.filename = paramString2; } public String getCharset() { return null; } public long getContentLength() { return this.data.length; } public String getFilename() { return this.filename; } public String getTransferEncoding() { return "binary"; } public void writeTo(OutputStream paramOutputStream) throws IOException { paramOutputStream.write(this.data); } }
如意料,httpclient4正常,ok,有了样本,那就离胜利不远了。开始分析。。。。
下载fiddler抓包,由于fiddler无法对java的应用抓包,需要额外设置下,分别对以上两个应用设置代理。
这里豆瓣使用的协议为https,需要进行认证,虽然可以通过注册一个自己的EasySSLProtocolSocketFactory跳过认证,但我们只是为了看下request报文的body,没必要捣鼓这些,将请求地址中的https改为http即可。
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, new HttpHost("127.0.0.1", 8888)); //httpclient4 client.getHostConfiguration().setProxy("127.0.0.1", 8888); //httpclient3
抓包获得的boundary如下:
httpclient3抓到的内容:
------------------314159265358979323846
Content-Disposition: form-data; name="image"; filename="upload.jpg"
Content-Type: image/jpeg ; charset=UTF-8
Content-Transfer-Encoding: binary
XXXXXXX图片bytesXXXXXXX
httpclient4抓到的内容:
--Ih2sX8QV86yWiK_Mux82mBVKkDLWVxG4
Content-Disposition: form-data; name="image"; filename="upload.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
XXXXXXX图片bytesXXXXXXX
可以看出来唯一的区别在于4比3少了一个“charset=UTF-8”,重写httpclient3的boundary输出,发表成功。。
看来是豆瓣接收上传的图片时没有完全按http1.1协议来。摔~~~~~~
重写httpclient3的boundary输出的方法,自定义一个自己的FilePart:
public class DoubanFileBase extends FilePart { public MyFileBase(String name, String fileName, File file, String contentType, String charset) throws FileNotFoundException { super(name, fileName, file, contentType, charset); } protected void sendContentTypeHeader(OutputStream out) throws IOException { String contentType = getContentType(); if (contentType != null) { out.write(CRLF_BYTES); out.write(CONTENT_TYPE_BYTES); out.write(EncodingUtil.getAsciiBytes(contentType)); } } }