zoukankan      html  css  js  c++  java
  • Http multipart/form-data多参数Post方式上传数据

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

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

    --(boundary的任意字符串)**********
    Content-Disposition: form-data; name="postKey"
    
    postValue
    --(boundary的任意字符串)**********
    Content-Disposition: form-data; name="postKey"; filename="file.getName()"
    Content-Type: image/png; charset=utf-8
    (文件的二进制数据)
    --(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相关的

        public static ResponseVo importForBatchAddDetailsPost(String requestUrl,String promoId,String operator, String filePath) {
            File file=new File(filePath);
            ResponseVo result = new ResponseVo();
            JSONObject json = new JSONObject();
            String BOUNDARY = "------WebKitFormBoundaryAl9CIOBJ1jfQWTl8";
            URL url;
    
            try {
                url = new URL(requestUrl);
                //SSLContext sc=SSLContext.getInstance("SSL");
                //sc.init(null,new TrustManager[] {new MyX509TrustManager()},new java.security.SecureRandom());
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                //urlConnection.setSSLSocketFactory(sc.getSocketFactory());
                //urlConnection.setHostnameVerifier(new TrustAnyHostnameVerifier());
                urlConnection.setUseCaches(false);
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoOutput(true);
                urlConnection.setDoInput(true);
                urlConnection.setRequestProperty("Connection","Keep-Alive");
                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");
                urlConnection.setRequestProperty("Charset","UTF-8");
                urlConnection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + "----WebKitFormBoundaryAl9CIOBJ1jfQWTl8");
                urlConnection.connect();
                StringBuilder contentBody1 = new StringBuilder();
                StringBuilder contentBody2 = new StringBuilder();
                String boundary = BOUNDARY+ "
    ";
                DataOutputStream out =new DataOutputStream(urlConnection.getOutputStream());
                byte[] end_data=("------WebKitFormBoundaryAl9CIOBJ1jfQWTl8--".getBytes());
                if (file != null) {
                    //第一部分参数:excel文件
                    contentBody1.append(boundary);
                    contentBody1.append("Content-Disposition: form-data; name="file"; filename="ActImportHouseTemplate.xlsx""+"
    ");
                    contentBody1.append("Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"+"
    ");
                    contentBody1.append("
    ");
    
                    out.write(contentBody1.toString().getBytes());
                    //读取excel文件
                    DataInputStream dis = new DataInputStream(new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[(int) file.length()];
                    bytes = dis.read(bufferOut);
                    out.write(bufferOut, 0, bytes);
                    out.write("
    ".getBytes());
                    dis.close();
                    //第二部分参数:其他参数promoId,operator
                    contentBody2.append(boundary);
                    contentBody2.append("Content-Disposition: form-data; name="promoId""+ "
    ");
                    contentBody2.append("
    ");
                    contentBody2.append(promoId+ "
    ");
                    contentBody2.append(boundary);
                    contentBody2.append("Content-Disposition: form-data; name="operator""+ "
    ");
                    contentBody2.append("
    ");
                    contentBody2.append(operator+ "
    ");
    
                    out.write(contentBody2.toString().getBytes());
                    out.write(end_data);
                    out.flush();
    
                    //从服务器获得回答的内容
                    InputStream inputStream=urlConnection.getInputStream();
                    InputStreamReader reader=new InputStreamReader(inputStream);
                    BufferedReader in=new BufferedReader(reader);
                    String strLine = "";
                    String strResponse = "";
                    while ((strLine = in.readLine()) != null) {
                        strResponse += strLine + "
    ";
                        json = JSON.parseObject(strResponse);
                    }
                        result.setJson(json);
                        out.close();
    
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //catch (NoSuchAlgorithmException e){}
            //catch (NoSuchProviderException e){}
            //catch (KeyManagementException e){}
            return result;
        }

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

    public class MyX509TrustManager implements X509TrustManager{
    
        public MyX509TrustManager(){}
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }
    
        public static SSLSocketFactory getSSFactory() throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException{
            TrustManager[] tm = { new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            return  ssf;
        }
    
    }
    public class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session){
            return true;
        }
    }

    具体这两个类是否好使,为什么这么写,我也不确定,如果只是简单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

  • 相关阅读:
    查看mysql版本的四种方法及常用命令
    newInstance和new的区别(good)
    Citrix 服务器虚拟化之六 Xenserver虚拟机创建与快照
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 2的次幂表示
    Java实现 蓝桥杯 算法训练 2的次幂表示
    Java实现 蓝桥杯 算法训练 前缀表达式
    Java实现 蓝桥杯 算法训练 前缀表达式
  • 原文地址:https://www.cnblogs.com/techfans/p/9335276.html
Copyright © 2011-2022 走看看