最近,工作中遇到需要使用java实现http发送get、post请求,简单的之前经常用到,但是这次遇到了上传文件的情况,之前也没深入了解过上传文件的实现,这次才知道通过post接口也可以,是否还有其他方式我还不知道。

下面来说具体问题,就是要通过接口post方式上传一个excel文件,另外还有其他2个参数,当然,对我来说就是这个文件不知道怎么传,后来通过网上的几篇文章了解到整个文件可以做为一个参数,通过chrome或抓包工具可以看到参数情况如下所示:

  1. --(boundary的任意字符串)**********
  2. Content-Disposition: form-data; name="postKey"
  3.  
  4. postValue
  5. --(boundary的任意字符串)**********
  6. Content-Disposition: form-data; name="postKey"; filename="file.getName()"
  7. Content-Type: image/png; charset=utf-8
  8. (文件的二进制数据)
  9. --(boundary的任意字符串)**********--

这个是引用网上那篇文章的,注意这里只有2个参数,第一个是普通参数,参数名师postKey,参数值是postValue。第二个参数则是要上传的文件,此处是一张图片,当然也可以是txt,excel都可以。这是chrome开发者工具中查看到的样子,注意这个(文件的二进制数据),在chrome里是看不到的,fiddler可以看到是一堆乱码,也就是说把文件转换成二进制字符串了。然后运行了一下,发现还是报错,报400错误,其实这应该指的还是参数格式不对,也就是我拼的这个参数的串格式还是有问题,但此时,我却猜测可能是https的问题,因为我需要调用的接口是https的,之前也是一直在搞http的,没有弄过https的,所以又是一番研究https,并且还得支持上传文件和多参数。后来,按照网上文章的说法引用了几个支持https的类,觉得应该https没问题了,但还是报400错误,于是猜测问题肯定出在字符串的格式上,最后,发现connection.SetRequestProperty时,设置的边界字符串与实际拼参数是的边界有差异,多了两个中划线,去掉后就post成功了,然后又回过头来看到底和https有没有关系,注释掉了所有关于https的代码,发现一样可以post成功,也就是说,至少我这接口虽然是要求https的,但java实现时可以不用考虑https,http就可以。下面贴出代码,注释掉的部分就是与https相关的

  1. public static ResponseVo importForBatchAddDetailsPost(String requestUrl,String promoId,String operator, String filePath) {
  2. File file=new File(filePath);
  3. ResponseVo result = new ResponseVo();
  4. JSONObject json = new JSONObject();
  5. String BOUNDARY = "------WebKitFormBoundaryAl9CIOBJ1jfQWTl8";
  6. URL url;
  7.  
  8. try {
  9. url = new URL(requestUrl);
  10. //SSLContext sc=SSLContext.getInstance("SSL");
  11. //sc.init(null,new TrustManager[] {new MyX509TrustManager()},new java.security.SecureRandom());
  12. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
  13. //urlConnection.setSSLSocketFactory(sc.getSocketFactory());
  14. //urlConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());
  15. urlConnection.setUseCaches(false);
  16. urlConnection.setRequestMethod("POST");
  17. urlConnection.setDoOutput(true);
  18. urlConnection.setDoInput(true);
  19. urlConnection.setRequestProperty("Connection","Keep-Alive");
  20. urlConnection.setRequestProperty("Uuser-Agent","Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36");
  21. urlConnection.setRequestProperty("Charset","UTF-8");
  22. urlConnection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + "----WebKitFormBoundaryAl9CIOBJ1jfQWTl8");
  23. urlConnection.connect();
  24. StringBuilder contentBody1 = new StringBuilder();
  25. StringBuilder contentBody2 = new StringBuilder();
  26. String boundary = BOUNDARY+ "\r\n";
  27. DataOutputStream out =new DataOutputStream(urlConnection.getOutputStream());
  28. byte[] end_data=("------WebKitFormBoundaryAl9CIOBJ1jfQWTl8--".getBytes());
  29. if (file != null) {
  30. //第一部分参数:excel文件
  31. contentBody1.append(boundary);
  32. contentBody1.append("Content-Disposition: form-data; name=\"file\"; filename=\"ActImportHouseTemplate.xlsx\""+"\r\n");
  33. contentBody1.append("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"+"\r\n");
  34. contentBody1.append("\r\n");
  35.  
  36. out.write(contentBody1.toString().getBytes());
  37. //读取excel文件
  38. DataInputStream dis = new DataInputStream(new FileInputStream(file));
  39. int bytes = 0;
  40. byte[] bufferOut = new byte[(int) file.length()];
  41. bytes = dis.read(bufferOut);
  42. out.write(bufferOut, 0, bytes);
  43. out.write("\r\n".getBytes());
  44. dis.close();
  45. //第二部分参数:其他参数promoId,operator
  46. contentBody2.append(boundary);
  47. contentBody2.append("Content-Disposition: form-data; name=\"promoId\""+ "\r\n");
  48. contentBody2.append("\r\n");
  49. contentBody2.append(promoId+ "\r\n");
  50. contentBody2.append(boundary);
  51. contentBody2.append("Content-Disposition: form-data; name=\"operator\""+ "\r\n");
  52. contentBody2.append("\r\n");
  53. contentBody2.append(operator+ "\r\n");
  54.  
  55. out.write(contentBody2.toString().getBytes());
  56. out.write(end_data);
  57. out.flush();
  58.  
  59. //从服务器获得回答的内容
  60. InputStream inputStream=urlConnection.getInputStream();
  61. InputStreamReader reader=new InputStreamReader(inputStream);
  62. BufferedReader in=new BufferedReader(reader);
  63. String strLine = "";
  64. String strResponse = "";
  65. while ((strLine = in.readLine()) != null) {
  66. strResponse += strLine + "\n";
  67. json = JSON.parseObject(strResponse);
  68. }
  69. result.setJson(json);
  70. out.close();
  71.  
  72. }
  73. } catch (IOException e) {
  74. // TODO Auto-generated catch block
  75. e.printStackTrace();
  76. }
  77. //catch (NoSuchAlgorithmException e){}
  78. //catch (NoSuchProviderException e){}
  79. //catch (KeyManagementException e){}
  80. return result;
  81. }

另外贴出https需要用到的两个类

  1. public class MyX509TrustManager implements X509TrustManager{
  2.  
  3. public MyX509TrustManager(){}
  4. @Override
  5. public void checkClientTrusted(X509Certificate[] arg0, String arg1)
  6. throws CertificateException {
  7. // TODO Auto-generated method stub
  8.  
  9. }
  10.  
  11. @Override
  12. public void checkServerTrusted(X509Certificate[] arg0, String arg1)
  13. throws CertificateException {
  14. // TODO Auto-generated method stub
  15.  
  16. }
  17.  
  18. @Override
  19. public X509Certificate[] getAcceptedIssuers() {
  20. // TODO Auto-generated method stub
  21. return null;
  22. }
  23.  
  24. public static SSLSocketFactory getSSFactory() throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException{
  25. TrustManager[] tm = { new MyX509TrustManager()};
  26. SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
  27. sslContext.init(null, tm, new java.security.SecureRandom());
  28. SSLSocketFactory ssf = sslContext.getSocketFactory();
  29. return ssf;
  30. }
  31.  
  32. }
  1. public class TrustAnyHostnameVerifier implements HostnameVerifier {
  2. public boolean verify(String hostname, SSLSession session){
  3. return true;
  4. }
  5. }

具体这两个类是否好使,为什么这么写,我也不确定,如果只是简单post一个https接口,可以参照下面这个文章:https://www.cnblogs.com/lichmama/p/6780298.html   其中用到的bing图片地址已经过期,可以用这个接口查找:https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1,最后拼出来的图片地址如:https://cn.bing.com/az/hprichbg/rb/ComicFans_ZH-CN10352835982_1920x1080.jpg

综上,总结如下:

1、java实现的http请求可以有很多种,除了常见的get、post,还可以上传文件

2、上传文件除了通过接口上传,应该还有其他方式

3、java实现http和https请求应该大多数是通用的

4、http上传文件,一定要注意参数字符串的拼接格式,主要有以下几点:

(1)边界的字符串是随机生成的,只要保证每个边界一样即可,注意只有最后一行边界是在末尾多出两个中划线的

(2)参数中的换行应该与抓包中的一致,据说是由严格要求,我也没试过不一致的情况

(3)参数的顺序是否无关紧要,这个我也没试过

最后贴出两篇参考文章的地址:

java实现https请求
https://www.cnblogs.com/lichmama/p/6780298.html
Http multipart/form-data多参数Post方式上传数据
https://blog.csdn.net/futianjie_china/article/details/53523814

Http multipart/form-data多参数Post方式上传数据的更多相关文章

  1. egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名

    egg.js 通过 form 和 ajax 两种方式上传文件并自定义目录和文件名 评论:10 · 阅读:8437· 喜欢:0 一.需求 二.CSRF 校验 三.通过 form 表单上传文件 四.通过 ...

  2. iframe和form表单实现ajax请求上传数据

    form的target属性设置为iframe的name值时,表示提交到url后返回的数据显示到iframe区域 <form action="/upload.html" met ...

  3. 通过Ajax方式上传文件,使用FormData进行Ajax请求

    通过传统的form表单提交的方式上传文件: <form id= "uploadForm" action= "http://localhost:8080/cfJAX_ ...

  4. [转] 通过Ajax方式上传文件,使用FormData进行Ajax请求

    通过传统的form表单提交的方式上传文件: <form id= "uploadForm" action= "http://localhost:8080/cfJAX_ ...

  5. 前端 - jquery方式 / iframe +form 方式 上传文件

    环境与上一章一样 jquery 方式上传文件: HTML代码 {#html代码开始#} <input type="file" id="img" > ...

  6. JavaScript实现form表单的多文件上传

    form表单的多文件上传,具体内容如下 formData对象可以使用一系列的键值对来模拟一个完整的表单,然后使用Ajax来发送这个表单 使用<form>表单初始化FormData对象的方式 ...

  7. C# HTTP系列13 以form-data方式上传多个文件以及键值对集合到远程服务器

    系列目录     [已更新最新开发文章,点击查看详细] 类似于以下场景,将表单中的用户信息(包含附件)上传到服务器并保存到数据库中, <form id="form1" run ...

  8. koa2:通过Ajax方式上传文件,使用FormData进行Ajax请求

    koa2通过表单上传的网上很多,但通过Ajax方式上传文件,使用FormData进行Ajax请求,不好找. 参考了这个用base64上传图片的例子.https://github.com/Yuki-Mi ...

  9. java模拟form上传数据

    Java模拟form表单上传 查看form表单提交的http请求为 import java.io.*; import java.net.*; public class FileUpload { /** ...

随机推荐

  1. C# WinForm的练习

    今天写了一个WinForm的练习,将源代码贴出来和大家一起学习学习. 首先:按照下图将一个button控件.三个RadioButton控件.三个CheckBox控件.一个Label控件和一个Track ...

  2. lua类实现

    _Account = {} --创建一张借记卡 function _Account:new( tb ) local _Tb = tb or {} setmetatable(_Tb, self) sel ...

  3. VPU硬编码

    平台是RK3066(福州瑞芯微公司),android 4.2.0,其实时VP8硬编码,与软件编码是ffpmeg,x264,xvid等软编码是有区别的.硬编码主要是依赖于硬件. 硬编码:通过调用Andr ...

  4. hdu1811 Rank of Tetris 拓扑排序+并查集

    这道题是拓扑排序和并查集的综合运用. 由于排行榜是一种从高到低的排序.所以在拓扑排序的时候,如果有一次加入的入度为零的点数大于1,就有变得不确定了(UNCERTAIN). 由于只有一棵树,当树的数量大 ...

  5. GEF入门笔记

    最近项目中需要用到Eclipse GEF框架进行画图,故将平时学习笔记更新到博客中,便于查阅 自己画的一个GEF基本结构     最基本流程 1.创建model(包括数据域.在界面中的布局.图片索引等 ...

  6. OnLineML:时序数据挖掘

    关于时序分析: 我们跟随时间的脚步,试图解释现在.理解过去.甚至预测未来........ 原文链接:http://blog.sciencenet.cn/home.php?mod=space&u ...

  7. JS 实现类似打印的效果(一个字一个字显示)

    <pre id="aa"></pre> <div style="display:none" id="w"> ...

  8. spring boot (一)

    spring boot 启动注解  @SpringBootApplication @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIM ...

  9. FFmpeg avcodec_send_packet压缩包函数

    首先看一下FFmpeg关于该packet函数的注释: int avcodec_send_packet ( AVCodecContext *  avctx,     const AVPacket *  ...

  10. 【JavaScript框架封装】数据类型检测模块功能封装

    数据类型检测封装后的最终模块代码如下: /*数据类型检验*/ xframe.extend(xframe, { // 鸭子类型(duck typing)如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭 ...