微信上传图片出现的问题和总结

前端之家收集整理的这篇文章主要介绍了微信上传图片出现的问题和总结前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

先说一下微信上传图片(这里讲的是新增临时素材)
在微信开发者文档中的被动回复用户消息的开头就说明了:

请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,只支持认证服务号。

多媒体消息有图片、语音、视频,也可以这样想:只有回复消息xml格式中存在media_id的都必须先上传到微信服务器,得到微信服务器返回的media_id,然后再用这个media_id来调用多媒体。

关于怎么上传多媒体文件,可以参考下面3个材料:
@L_403_0@
微信公众号上传下载网络路径下的多媒体文件-java
微信公众号上传本地路径下的多媒体文件
我将本地路径和网络路径多媒体文件结合起来了,代码如下:

public class MediaUtil {

    /** * 上传多媒体文件 * @param access_token 接口访问凭证 * @param mediaType 媒体文件类型,分别有图片(image)、语音(voice)、视频(video) * @param mediaUrl * 媒体文件的url ,本地路径和网络路径的文件都能上传 * * 图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式, * 语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 * @return */
    public static WeiXinMedia uploadMedia(String access_token,String mediaType,String mediaUrl) {
        //返回数据
        String result = "";

        // 拼接上传地址uploadUrl
        String uploadUrl = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
        uploadUrl = uploadUrl.replace("ACCESS_TOKEN",access_token).replace(
                "TYPE",mediaType);

        try {
            // 创建一个https连接
            URL requstUrl = new URL(uploadUrl);
            HttpsURLConnection conn = (HttpsURLConnection) requstUrl.openConnection();

            conn.setRequestMethod("POST");//设置请求方式
            conn.setUseCaches(false);
            conn.setDoInput(true);
            conn.setDoOutput(true);

            //设置请求消息头
            conn.setRequestProperty("Connection","Keep-Alive");
            conn.setRequestProperty("Charset","UTF-8");
            String boundary = "----" + System.currentTimeMillis();//分隔字符串
            conn.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary);


            //拼接请求消息体的格式头
            StringBuilder sb1 = new StringBuilder();
            sb1.append("--");
            sb1.append(boundary);
            sb1.append("\r\n"); //回车
            sb1.append("Content-Disposition:form-data;name=\"file\";filename=\""+mediaUrl+"\"\r\n");//回车
            sb1.append("Content-Type:application/octet-stream\r\n");//回车
            sb1.append("\r\n");//回车 - 空行

            byte[] head = sb1.toString().getBytes("UTF-8");

            //获得连接的写入流out
            DataOutputStream out = new DataOutputStream(conn.getOutputStream());

            //将请求消息体的格式头写入conn的写入流outout.write(head);


            //读数据要用的
            int len = 0;
            byte[] buf = new byte[1024];

            //>>>>>>>>>>判断mediaUrl是本地路径还是网络路径
            if(mediaUrl.startsWith("http")){
                URL url2 = new URL(mediaUrl);
                HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
                conn2.setDoInput(true);
                conn2.setRequestMethod("GET");

                BufferedInputStream bis = new BufferedInputStream(conn2.getInputStream());
                while((len = bis.read(buf))>0){
                    out.write(buf,0,len);
                }
                bis.close();
                conn2.disconnect();

            }else{
                //将请求消息体的正文写入conn的写入流out中
                DataInputStream in = new DataInputStream(new FileInputStream(mediaUrl));
                while((len = in.read(buf))>0){
                    out.write(buf,len);
                }
                in.close();//关闭
            }

            System.out.println("文件写入完成 ...");

            //拼接请求消息体的格式尾
            StringBuilder sb2 = new StringBuilder();
            sb2.append("\r\n");//回车 - 请求消息体的正文和格式头、格式尾分别隔着一个空行
            sb2.append("--");
            sb2.append(boundary);
            sb2.append("--");
            sb2.append("\r\n");//回车

            byte[] foot = sb2.toString().getBytes("UTF-8");
            //System.out.println(foot);
            //将请求消息体的格式尾写入outout.write(foot);
            out.flush();
            out.close();

            System.out.println("上传多媒体请求消息发出 ...");

            //读取服务器响应的消息
            StringBuffer temp = new StringBuffer();
            InputStream respIn = conn.getInputStream();
            len = 0;
            while((len = respIn.read(buf))>0){
                temp.append(new String(buf,len));
            }
            respIn.close();
            conn.disconnect();

            result = temp.toString();

        } catch (IOException e) {
             System.out.println("发送POST请求出现异常!" + e); 
             e.printStackTrace(); 
        }
        System.out.println("微信服务器回复的消息:" + result);
        JSONObject json = JSONObject.fromObject(result);

        //组装WeiXinMedia
        WeiXinMedia wxMedia = new WeiXinMedia();
        wxMedia.setType(json.getString("type"));
        wxMedia.setMedia_id(json.getString("media_id"));
        wxMedia.setCreated_at(json.getInt("created_at"));

        return wxMedia;
    }
}

WeiXinMedia的代码如下:

public class WeiXinMedia {
    private String type;
    private String media_id;
    private int created_at;
    //省略setter和getter

如果对其中的上传文件的http消息格式不明白,可以参考:
理解Http消息头 - 看 4 Post 小节

说了半天,故事才开始

有了MediaUtil那我还不大干一场,在CoreService类中

Image image = new Image();
        image.setMediaId(MediaUtil.uploadMedia(access_token,"image","c:/1.png").getMedia_id());
ImageRespMessage imageRespMessage = new ImageRespMessage();
            imageRespMessage.setToUserName(fromUserName);
            imageRespMessage.setFromUserName(toUserName);
            imageRespMessage.setCreateTime(new Date().getTime());
            imageRespMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_IMAGE);
            imageRespMessage.setImage(image);


            respXml = MessageUtil.respMessage2Xml(imageRespMessage);

Image类中只有一个属性media_id,有图有真相

public class Image {
    public String MediaId;
    //setter和getter
}

ImageRespMessage代码如下:

public class ImageRespMessage extends BaseRespMessage {
    private Image image;
    //setter和getter
}

然后就运行嘛,试几次都是“该公众号暂时无法提供服务,请稍后再试”这样的系统提示,我就纳闷了,怎么是我文件上传成功,在”使用网页调试工具调试该接口”中测试了一下,图片妥妥的传给了微信服务器,证明access_token和media_id是有效的,那为什么还有系统提示呢?

请开发者注意,一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

1、开发者在5秒内未回复任何内容
2、开发者回复了异常数据,比如JSON数据等

好的,微信服务器给出了答案。
首先我的服务器是不是5秒内没有回复呢?没有,绝对没有没回复。因为回复的xml数据好好的打印了出来。如下:

<xml>
  <ToUserName><![CDATA[oBIBht8GBKmMk5os5xF4U_SvmhdY]]></ToUserName>
  <FromUserName><![CDATA[gh_48efdea48052]]></FromUserName>
  <CreateTime><![CDATA[1429841278925]]></CreateTime>
  <MsgType><![CDATA[image]]></MsgType>
  <image>
    <MediaId><![CDATA[F-KFiCTQIzfdAWlChSIhaVCbWbVq3oTy-NHeIq7G0vk5BYDU_P4JFbf2drv0eNSs]]></MediaId>
  </image>
</xml>

那就是回复了数据异常的事了?
对照着微信开发者文档瞅了好几遍,终于被我发现了。都瞅瞅!下面的xml格式和上面的有什么不同?

<xml>
  <ToUserName><![CDATA[oBIBht8GBKmMk5os5xF4U_SvmhdY]]></ToUserName>
  <FromUserName><![CDATA[gh_48efdea48052]]></FromUserName>
  <CreateTime><![CDATA[1429841278925]]></CreateTime>
  <MsgType><![CDATA[image]]></MsgType>
  <Image>
    <MediaId><![CDATA[F-KFiCTQIzfdAWlChSIhaVCbWbVq3oTy-NHeIq7G0vk5BYDU_P4JFbf2drv0eNSs]]></MediaId>
  </Image>
</xml>

唯一的区别就是节点是首字母是大写的,是小写的,小写的不符合微信服务器的规范,所以就被列为异常消息了。

所以在封装消息时,一定要注意属性名称是否和微信规范一样,最好的就是直接从微信开发者文档上复制。(话说我也发现微信开发者文档上有错别字,我也不知道对不对了,大家看看,“纬度”的“纬”在文档中打成了“维度”)。

出现错误时,把回复的xml数据打印出来和文档上的仔细对比,一个字符一个字符的对比,实在不行,写个程序equals一把。

猜你在找的XML相关文章