填写的内容微信没有查询的接口,备案成功了才有一个查询备案详情的接口。 所以稳妥的做法是:需要一个表把备案提交的信息存起来。 例如: 提交备案这个表单的数据,用一个表的字段存起来。 [图片] 下次,要重复提交备案后,表单数据可以加载出来,用于回显数据。而不是一个一个字段地重填,效率太低了。
提交备案后撤回了备案但是从重新提交一直限制我已经提交了,撤回也提示备案审核订单处于未可撤回状态提交备案后撤回了备案但是从重新提交一直限制我已经提交了,撤回也提示备案审核订单处于未可撤回状态
2024-04-29请大家留意这个文章的回复,我将源码也附上了,接口没有什么问题,大家没有完全理解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