加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 09:11:06 所属栏目:百科 来源:网络整理
导读:先说一下微信上传图片(这里讲的是新增临时素材) 在微信开发者文档中的被动回复用户消息的开头就说明了: 请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,只支持认证服务号。 多媒体消息有图片、语音、视频,也可以这样想:只有回复消

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

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

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

关于怎么上传多媒体文件,可以参考下面3个材料:
微信开发者文档中的新增临时素材
微信公众号上传下载网络路径下的多媒体文件-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("rn"); //回车
            sb1.append("Content-Disposition:form-data;name="file";filename=""+mediaUrl+""rn");//回车
            sb1.append("Content-Type:application/octet-streamrn");//回车
            sb1.append("rn");//回车 - 空行

            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("rn");//回车 - 请求消息体的正文和格式头、格式尾分别隔着一个空行
            sb2.append("--");
            sb2.append(boundary);
            sb2.append("--");
            sb2.append("rn");//回车

            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一把。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读