无论是小程序还是公众号 模板消息这个很奇葩,一次性订阅要求每授权一次才能发送一次,而长期订阅又只开放给一些企事业行政机构,有种店大欺客的感觉, 终极方向是搞一款APP, 不再给这些社交APP做嫁衣。 权衡再三 使用短信服务了, 通知短链接跳转至小程序,平均下来,一条信息6分钟左右, 10万用户的话的话,一个用户一天2条短信, 就是10,00,00 X 6 X2 分钱,合计: 12000元,即 10万用户一天短信的消耗就是 12000元,的确是很大开销,要么:这笔钱得转嫁至使用方,要么: 用户在小程序中搞个消息提醒,用户打开小程序才可查看。
关于4月30日取消服务号模板消息通知替代方案的可行性问题请教?您好,我们是做餐饮服务行业的,我们的商家的员工是通过使用服务号的模板消息来接收客户的下单通知并进行处理的(员工不可能人手一台电脑),像这种非营销场景应该用什么方案替代呢?我们看到你们开放了订阅消息,但仅限一次,长期的限制了行业,而员工不可能每一次消息都点授权吧,请问类似这样的问题我们如何处理呢?有没有什么替代方案,如果没有将对我们进行的是毁灭性打击,我们能想到的是只能自己开发一款app了,但是这个成本又太高我们承担不了。
06-21填写的内容微信没有查询的接口,备案成功了才有一个查询备案详情的接口。 所以稳妥的做法是:需要一个表把备案提交的信息存起来。 例如: 提交备案这个表单的数据,用一个表的字段存起来。 [图片] 下次,要重复提交备案后,表单数据可以加载出来,用于回显数据。而不是一个一个字段地重填,效率太低了。
提交备案后撤回了备案但是从重新提交一直限制我已经提交了,撤回也提示备案审核订单处于未可撤回状态提交备案后撤回了备案但是从重新提交一直限制我已经提交了,撤回也提示备案审核订单处于未可撤回状态
04-29<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.16.0</version> </dependency> 在你的WEB工程中引入如上commons-codec版本。 如果引入的依赖包有与之冲突的版本,请使用 <exclusion> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </exclusion> 将冲突的包排除掉。 微信加密推过来的报文如下: <xml> <AppId><![CDATA[wxXXXXX]]></AppId> <Encrypt><![CDATA[iEmcIRyvpIxajr4knyDDch36Vf2EYzaP+czY/ku/+2XXDVl9BF54U3y+fZleAClXaHR9Em2yQcVJrx0kou8F9xjJA6O1xq2mN4BawPsdATqCEKY16ZExcuexBvG9NHS82+qI0JlGAw8CvHibNCNftZYuRO6bgGv0nUrUn1gr1zCwDDA5Gh1xFAute+p17WndpgNLrOUGtbxgYaL7shZLKE/MRzPmzYLqngjYP7oj215B1axbf02E0d0T0jAvkAY9zNheMF7cWZCSUGGsogm/C1KXCDQ4nlL5E/V4oUt2cp8fBDZXGSR7cWj9r0V/3L6hMdoAmF3onx9AbQx4yuV3qcppiYX4TAjEi4v7zJ09RrOaVegS0HkVNiS1RCVpsjGMCw+eA25uWr+36QXJGKGH7QJG5uA/b1WZCi0RPaC9QepMO+O5CJJAYva034CGa1L4xDu7VPH+CpCrBDD97Z8ZNQ==]]></Encrypt> </xml> 篇幅有限 有不明白的加微信进一步交流: comeon_betty
EncodingAESKey用commons-codec:1.13解密不了消息解密时,EncodingAESKey用commons-codec:1.13解密不了。 参考:https://developers.weixin.qq.com/community/develop/doc/0002a00b7bcd088eeb89f4d485b000 https://developers.weixin.qq.com/community/develop/doc/000e46d10d0050aa6559aec3a56400?_at=1578900243140 这问题之前就有人提过了,你们就说你们改不改,你们不改我就把消息加解密方式设置为明文了。 搞个东西是给开发者用的,不是给自己用的,别人用不了这API有什么意义呢?你们的开发人员自己写着玩呢?
2023-11-17同问:平台型小程序是代商家开发的, 是不是商家提供食品经营许可证就可以了?
请问电商服务平台的小程序,也需要办理食品经营许可证吗?请问电商服务平台的小程序,线上的产品或食品,都是加入的商家的,自家不做产品销售,只提供产品销售平台服务,这样 商户也需要办理食品经营许可证吗?
2023-10-11请大家留意这个文章的回复,我将源码也附上了,接口没有什么问题,大家没有完全理解https://developers.weixin.qq.com/community/develop/doc/0008ac553d49d02208504ad8664400
上传小程序备案媒体材料 返回41005?array:4 [▼ "type" => "image" "certificate_type" => 1 "icp_order_field" => "icp_subject.organize_info.certificate_photo" "media" => CURLFile {#1677 ▼ +name: "D:\svn\hjk_saas\trunk\server_source\public\uploads\wxappapply\bb588ce35ab1a1cd79020726304d9aa1.png" +mime: "" +postname: "" } ] array:2 [▼ "errcode" => 41005 "errmsg" => "media data missing, hint: [520b2e54-e043-4f46-9b06-25e134b4b005] rid: 65026dc0-15ab53a6-3d590fca"]
2023-10-09请留意这个文章,我已将自己的分享及源码附上, 接口完全没有问题 https://developers.weixin.qq.com/community/develop/doc/0008ac553d49d02208504ad8664400
第三方服务商备案上传媒体接口材料文档有问题当需要填写 [代码]certificate_type[代码] 字段时,如果和 [代码]icp_order_field[代码] 无法对应,则会上传失败,例如:当上传身份证头像面时,[代码]icp_order_field[代码] 填了 [代码]"icp_subject.principal_info.certificate_photo_front"[代码],[代码]certificate_type[代码] 必须填 [代码]2[代码] (居民身份证),如果填其它值,则会在使用该 [代码]media_id[代码] 调用申请小程序备案接口时报错,或上传失败。我使用实例 icp_order_field:icp_subject.principal_info.certificate_photo_front,certificate_type:2 提示上传失败
2023-10-09最近我在开发小程序备案这块功能涉及到上传备案材料,我可以将自己的实现分享出来 。使用的是响应式编程。 先看接口层: @RequestMapping(value = {"/security_superadmin/mini/icp/media/upload"}, method = RequestMethod.POST) public Mono image_upload(@RequestPart("file") Mono filePartMono, @RequestParam(value="component_appid",required = true) String component_appid, @RequestParam(value="authorizer_appid",required = true) String authorizer_appid, @RequestHeader(value="admintoken", required = true) String token, @RequestHeader("Content-Length") long contentLength, @RequestParam(value="type",required = true) String type, @RequestParam(value="certificate_type",required = true) String certificate_type, @RequestParam(value="icp_order_field",required = true) String icp_order_field ) throws Throwable { return wechatPlatformService.uploadMediaFile( filePartMono, component_appid, authorizer_appid, type, certificate_type, icp_order_field).map(res -> res); } 再看服务层: public Mono uploadMediaFile(Mono filePartMono , String component_appid, String authorizer_appid, String type, String certificate_type, String icp_order_field) throws Throwable { return filePartMono.doOnNext(fp -> log.info("Receiving File:{}" ,fp.filename())).flatMap(filePart -> { PlatformGrant grant = null; try { grant = super.getApiToken(component_appid, authorizer_appid); } catch (Exception e) { return Mono.just(Response.error(e)); } String url = "https://api.weixin.qq.com/wxa/icp/upload_icp_media?access_token=" + grant.getAuthorizer_access_token(); log.info("---> url {}", url); log.info("---->go here <----"); File temFile = new File("/tmp"); if (!temFile.exists()) { temFile.mkdirs(); } File upFile = new File(temFile + "/" + UUID.randomUUID() + ".jpg"); if (!upFile.exists()) { try { upFile.createNewFile(); } catch (Exception e) { return Mono.just(Response.error("上传文件异常:" + e.getMessage())); } } filePart.transferTo(upFile); byte[] bytes = null; try { bytes = Files.readAllBytes(upFile.toPath()); } catch (Exception e) { return Mono.just(Response.error("上传文件异常:" + e.getMessage())); } HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); HttpHeaders pictureHeader = new HttpHeaders(); pictureHeader.setContentDispositionFormData("file",upFile.getName()); pictureHeader.setContentType(MediaType.IMAGE_PNG); ByteArrayResource bar = new ByteArrayResource(bytes); HttpEntity picturePart = new HttpEntity<>(bar, pictureHeader); MultiValueMap multipartRequest = new LinkedMultiValueMap<>(); multipartRequest.add("media", picturePart); multipartRequest.add("type", type); multipartRequest.add("certificate_type", certificate_type); multipartRequest.add("icp_order_field", icp_order_field); HttpEntity entity = new HttpEntity(multipartRequest, headers); JSONObject json = restTemplate.postForObject(url, entity, JSONObject.class); log.info("--->上传备案媒体素材结果{}", json.toJSONString()); if (upFile.exists()){ upFile.delete(); log.info("---->删除文件<----"); } Integer errocode = json.getInteger("errcode"); if (0 == errocode.intValue()) { MiniMediaRecord record = new MiniMediaRecord(); record.setMedia_id(json.getString("media_id")); record.setType(type); record.setAuthorizer_appid(authorizer_appid); record.setComponent_appid(component_appid); record.setAuthorizer_appname(grant.getMuch_mini_name() != null ? grant.getMuch_mini_name() : ""); record.setCert_type(certificate_type); record.setSubmit_time(new Date()); record.setIcp_order_field(icp_order_field); miniMediaRecordRepository.save(record); } return Mono.just(Response.success("success")); }).then(Mono.just(Response.success("success"))); } 需要注意的是: 微信官方的这个接口不能以JSON格式提交参数,使用 restTemplate 需要 构造出一个 HttpEntity<ByteArrayResource> 对象。 HttpEntity picturePart = new HttpEntity<>(bar, pictureHeader); UI 界面: [图片] 响应结果: [图片] 希望有帮助。 欢迎加我微信:comeon_betty 来交流学习。
第三方平台上传小程序备案媒体材料?[图片] 这里是什么才行,实在没搞懂
2023-10-09已经解决。 代商家获取小程序详情接口,在这分享一下: @RequestMapping(value = {"/qurey/minin/info"}, method = RequestMethod.POST) public JSONObject queryMiniNameStatus(@RequestBody JSONObject body) { try { return wechatPlatformService.queryMiniInfo(body); } catch (Exception e) { log.error(StackTool.error(e, 100)); return new JSONObject().fluentPut("resCode", Constants.KEY_OP_FAIL).fluentPut("resMsg", e.getMessage()); } } /** * 查询小程序名称设置状态 * * @param body * @return * @throws Exception * */ public JSONObject queryMiniInfo(JSONObject body) throws Exception { String component_appid = body.getString("component_appid"); String authorizer_appid = body.getString("authorizer_appid"); PlatformGrant grant = getApiToken(component_appid, authorizer_appid); HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=utf-8"); headers.setContentType(type); headers.add("Accept", MediaType.APPLICATION_XML.toString()); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); String url = "https://api.weixin.qq.com/cgi-bin/account/getaccountbasicinfo?access_token=" + grant.getAuthorizer_access_token(); body.remove("component_appid"); body.remove("authorizer_appid"); HttpEntity<JSONObject> formEntity = new HttpEntity<JSONObject>(body, headers); JSONObject res = restTemplate.postForObject(url, formEntity, JSONObject.class); log.info("---->小程序基本信息查询 res {}", res); Integer status = res.getInteger("errcode"); JSONObject head_image_info = res.getJSONObject("head_image_info"); if (head_image_info != null) { String head_image_url = head_image_info.getString("head_image_url"); if ( StringUtils.isEmpty(grant.getHead_image_url()) ) { grant.setHead_image_url(head_image_url); platformGrantRepository.save(grant); log.info("--->更新小程序的图像<---- {}",head_image_url); } } JSONObject result = new JSONObject(); if (status != null && status.intValue() == 0) { result.put("resCode", "0"); result.put("resMsg", "OK"); result.put("result", res); } else { result.put("resCode", Constants.KEY_OP_FAIL); result.put("resMsg", res.getString("errmsg")); } return result; } 其中,获取第三方授权的 access_token 放在缓存中,过期了才向微信获取,并且持久化到表 PlatformGrant 中。以下是源码参照: /** * 获取/刷新接口调用令牌 * @param component_appid: 第三方平台appid * @param grant: * @return */ public PlatformGrant getApiToken(String component_appid, String authorizer_appid) throws Exception { String component_access_token = getComponentAccessToken(component_appid); PlatformGrant grant = getPlarformGrant(component_appid,authorizer_appid) ; if (grant == null) { throw new RuntimeException("平台未保存用户的授权信息"); } // 先不着急重新调用接口获取 if ( grant.getExpires_in() != null && grant.getUpdate_time() != null) { if (DateUtil.valid(grant.getUpdate_time(), grant.getExpires_in())){ // 没有过期 return grant; } } HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=utf-8"); headers.setContentType(type); headers.add("Accept", MediaType.APPLICATION_JSON.toString()); JSONObject reqBody = new JSONObject(); reqBody.put("component_access_token", component_access_token); reqBody.put("component_appid", component_appid); reqBody.put("authorizer_appid", authorizer_appid); reqBody.put("authorizer_refresh_token", grant.getAuthorizer_refresh_token()); HttpEntity<JSONObject> formEntity = new HttpEntity<JSONObject>(reqBody, headers); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); String url = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token="+component_access_token; JSONObject json = restTemplate.postForObject(url, formEntity, JSONObject.class); log.info(">>>授权码获取授权信息 返回:{}",json); if ( json.getIntValue("errcode") != 0 ) { // {"errcode":61023,"errmsg":"refresh_token is invalid rid: 6228c03e-19027c0c-7a98021d"} if (json.getString("errmsg").indexOf("refresh_token is invalid") != -1) { //需要从数据库取 } } String authorizer_access_token = json.getString("authorizer_access_token"); String authorizer_refresh_token = json.getString("authorizer_refresh_token"); int expires_in = json.getIntValue("expires_in"); grant = new PlatformGrant(); grant.setComponent_appid(component_appid); grant.setAuthorizer_access_token(authorizer_access_token); grant.setAuthorizer_appid(authorizer_appid); grant.setAuthorizer_refresh_token(authorizer_refresh_token); grant.setExpires_in(expires_in); return savePlatformGrant(grant); } 先从缓存中获取商家授权acess_token,获取不到或过期了再实时查询 /** * 获取平台 component_access_token 有效期2h * @return */ public String getComponentAccessToken(String appId) { WechatToken token = null; String key= RedisTool.getComponentAccessTokenKey(appId); //先从缓存中取: try { token =( WechatToken)redisTemplate.opsForValue().get(key); if( null != token) { log.info("---成功获取ComponetAccessToken:{}",token.toString()); return token.getToken(); } }catch(Exception e) { log.warn("----->getComponentAccessToken异常<-----"); log.error(StackTool.error(e,100)); } log.info("--缓存中未获取到ComponetAccessToken 即时查询接口 ----" ); String url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token"; JSONObject reqBody = new JSONObject(); String appSecret = null; if (appId.equals(wXBizMsgCrypt.getAppId())) { appSecret = wXBizMsgCrypt.getAppSecret(); }else{ MuchApiWechat api = muchApiWechatRepository.findMuchApiWechat(appId); if (api == null) { throw new RuntimeException("平台没有配置第三方小程序"); // wxc24950555e542854 } appSecret = api.getAppsecret(); } reqBody.put("component_appid", appId); reqBody.put("component_appsecret", appSecret); String component_verify_ticket = getComponentVerifyTicket(appId); if (StringUtils.isEmpty(component_verify_ticket)) { throw new RuntimeException("component_verify_ticket为空,请联系平台技术人员"); } reqBody.put("component_verify_ticket", component_verify_ticket); HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=utf-8"); headers.setContentType(type); headers.add("Accept", MediaType.APPLICATION_XML.toString()); HttpEntity<JSONObject> formEntity = new HttpEntity<JSONObject>(reqBody, headers); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); JSONObject result = restTemplate.postForObject(url, formEntity, JSONObject.class); log.info(">>>获取令牌返回: result="+result); // result={"errcode":61004,"errmsg":"access clientip is not registered requestIP: XX rid: 63a0f0bf-21116836-466eea46"} Integer errcode = result.getInteger("errcode") ; if (errcode != null && errcode.intValue() != 0) { throw new RuntimeException(result.getString("errmsg")); } String component_access_token = result.getString("component_access_token"); if (!StringUtils.isEmpty(component_access_token)) { Long now=System.currentTimeMillis()/1000; token = new WechatToken(now,component_access_token ); try{ redisTemplate.opsForValue().set(key, token , 7200, TimeUnit.SECONDS); }catch(Exception e){ log.warn("redis component_access_token 异常"); } } log.info("---->第三方平台 access_token:{}", component_access_token); return component_access_token; } 最后, 通过第三方平台来管理商家微信小程序,也可以由商家来自助管理。如:设置小程序图像、小程序介绍等信息。贴一张图片大家看看效果。微信的接口调用正确了还是非常稳定的。 之所以调用出错是没有使用商家的授权 authorizer_access_token [图片]
设置小程序隐私 48001 api unauthorized第三方平台小程序开发遇到问题,当第三方平台调用商家授权小程序时,可以正常返回 : 这里:授权小程序APPID及平台APPID {"authorizer_appid": "wx6a79d9e20634b4fb", componet_appid: "wxc24950555e542854"} 授权商家小程序ID: wx6a79d9e20634b4fb (这个小程序是通过快速创建企业小程序接口创建的,商家也已授权) 调用小程序详情接口:https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=" + component_access_token; 返回如下: API权限集ID:18 已经拿到。 { "authorizer_info": { "nick_name": "", "service_type_info": { "id": 0 }, "verify_type_info": { "id": 0 }, "user_name": "gh_61f6bc98c7a7", "alias": "", "qrcode_url": "http://mmbiz.qpic.cn/mmbiz_jpg/GAUFLLdxPuNsnVPvMkZSzGWu8QGpHdkpJkFnvnl9TJzYibLic4bBM0dTJxPNWwdnPmRxnH4InG3JgUDvU0yfrTag/0", "business_info": { "open_pay": 1, "open_shake": 0, "open_scan": 0, "open_card": 0, "open_store": 0 }, "idc": 1, "principal_name": "佛山市花梵花艺设计有限公司", "signature": "", "MiniProgramInfo": { "network": { "RequestDomain": [], "WsRequestDomain": [], "UploadDomain": [], "DownloadDomain": [], "BizDomain": [], "UDPDomain": [], "TCPDomain": [], "PrefetchDNSDomain": [], "NewRequestDomain": [], "NewWsRequestDomain": [], "NewUploadDomain": [], "NewDownloadDomain": [], "NewBizDomain": [], "NewUDPDomain": [], "NewTCPDomain": [], "NewPrefetchDNSDomain": [] }, "categories": [], "visit_status": 0 }, "register_type": 6, "account_status": 1, "basic_config": { "is_phone_configured": false, "is_email_configured": false } }, "authorization_info": { "authorizer_appid": "wx6a79d9e20634b4fb", "authorizer_refresh_token": "refreshtoken@@@DUewg9oNgD22AYF8hgS1Tv5UF4uVnpWHVkEeXjXsM-0", "func_info": [ { "funcscope_category": { "id": 17 } }, { "funcscope_category": { "id": 18 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 19 } }, { "funcscope_category": { "id": 25 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 30 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 31 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 36 } }, { "funcscope_category": { "id": 37 } }, { "funcscope_category": { "id": 40 } }, { "funcscope_category": { "id": 41 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 45 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 48 } }, { "funcscope_category": { "id": 49 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 51 } }, { "funcscope_category": { "id": 52 } }, { "funcscope_category": { "id": 57 } }, { "funcscope_category": { "id": 65 } }, { "funcscope_category": { "id": 67 } }, { "funcscope_category": { "id": 70 } }, { "funcscope_category": { "id": 71 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 73 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 76 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 81 }, "confirm_info": { "need_confirm": 0, "already_confirm": 0, "can_confirm": 0 } }, { "funcscope_category": { "id": 84 } }, { "funcscope_category": { "id": 85 } }, { "funcscope_category": { "id": 86 } }, { "funcscope_category": { "id": 88 } }, { "funcscope_category": { "id": 93 } }, { "funcscope_category": { "id": 99 } }, { "funcscope_category": { "id": 102 } }, { "funcscope_category": { "id": 104 } }, { "funcscope_category": { "id": 105 } }, { "funcscope_category": { "id": 112 } } ] } } 接着,调用: https://api.weixin.qq.com/wxa/gettemplatedraftlist?access_token= 商家授权的appid ( authorizer_appid ) 返回: 48001 api unauthorized 请帮我定位一下问题,谢谢! 微信: 13926003676
2023-02-03