在开发微信小程序中,发布审核的时候官方审核要求要对用于UGC生成的内容做安全审核,对违规内容进行处理,这里用到了官方给出的文本内容安全识别和多媒体内容安全识别,这次是基于java后端去实现的,过去的文章有写用云开发调用,可以参考以前的文章。
码字不易,看之前麻烦点个赞赞~谢谢!
文本内容安全识别
接口应在服务器端调用,不可在前端(小程序、网页、APP等)直接调用,具体可参考接口调用指南。
接口英文名:msgSecCheck
该接口用于检查一段文本是否含有违法违规内容。
应用场景:
- 用户个人资料违规文字检测;
- 媒体新闻类用户发表文章,评论内容检测;
- 游戏类用户编辑上传的素材(如答题类小游戏用户上传的问题及答案)检测等
查询参数 Query String Parameters
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| access_token | string | 是 | 接口调用凭证 |
请求体 Request Payload
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| content | string | 是 | 需检测的文本内容,文本字数的上限为2500字,需使用UTF-8编码 |
| version | number | 是 | 接口版本号,2.0版本为固定值2 |
| scene | number | 是 | 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志) |
| openid | string | 是 | 用户的openid(用户需在近两小时访问过小程序) |
| title | string | 否 | 文本标题,需使用UTF-8编码 |
| nickname | string | 否 | 用户昵称,需使用UTF-8编码 |
| signature | string | 否 | 个性签名,该参数仅在资料类场景有效(scene=1),需使用UTF-8编码 |
3. 返回参数
返回体 Response Payload
| 参数名 | 类型 | 说明 |
|---|---|---|
| errcode | number | 错误码 |
| errmsg | string | 错误信息 |
| detail | objarray | 详细检测结果 |
| trace_id | string | 唯一请求标识,标记单次请求 |
| result | object | 综合结果 |
解析
首先是查询参数access_token这个怎么获取?
XpayUtils.java
java
public String getAccessToken() throws Exception {
long now = System.currentTimeMillis();
if (cachedAccessToken != null && now < tokenExpireMillis) return cachedAccessToken;
synchronized (this) {
now = System.currentTimeMillis();
if (cachedAccessToken != null && now < tokenExpireMillis) return cachedAccessToken;
String url = "https://api.weixin.qq.com/cgi-bin/token"
+ "?grant_type=client_credential"
+ "&appid=" + XpayConfig.APP_ID
+ "&secret=" + XpayConfig.APP_SECRET;
String raw = restTemplate.getForObject(url, String.class);
JSONObject json = JSONObject.fromObject(raw);
if (!json.containsKey("access_token")) {
throw new Exception("获取 access_token 失败:" + raw);
}
cachedAccessToken = json.getString("access_token");
long expiresIn = json.getLong("expires_in");
tokenExpireMillis = now + (expiresIn - 300) * 1000L;
return cachedAccessToken;
}
}
XpayConfig.java
java
public class XpayConfig {
// 小程序 AppID / AppSecret
public static final String APP_ID = "";
public static final String APP_SECRET = "";
}
然后是文本内容安全接口实现
java
// ==================== 文本 msg_sec_check ====================
@Data
@NoArgsConstructor
public static class TextSecCheckReq {
/** 需检测文本,≤2500 字,UTF-8 */
private String content;
/** 接口版本,2.0 固定为 2 */
private Integer version;
/** 场景:1资料 2评论 3论坛 4社交日志 */
private Integer scene;
/** 用户 openid(近两小时需访问过小程序) */
private String openid;
private String title;
private String nickname;
/** 个性签名,仅 scene=1 有效 */
private String signature;
}
/**
* 文本内容安全识别(转发 POST https://api.weixin.qq.com/wxa/msg_sec_check)
*/
@PostMapping("/text/check")
public String textSecCheck(@RequestBody TextSecCheckReq req) {
IsInterface<JSONObject> res = new IsInterface<>();
try {
if (req.getContent() == null || req.getContent().trim().isEmpty()) {
res.setCode("fail");
res.setMsg("content不能为空");
return String.valueOf(JSONObject.fromObject(res));
}
String text = req.getContent();
if (text.length() > 2500) {
res.setCode("fail");
res.setMsg("content超过2500字上限");
return String.valueOf(JSONObject.fromObject(res));
}
if (req.getScene() == null
|| req.getOpenid() == null || req.getOpenid().trim().isEmpty()) {
res.setCode("fail");
res.setMsg("scene、openid不能为空");
return String.valueOf(JSONObject.fromObject(res));
}
int version = req.getVersion() != null ? req.getVersion() : 2;
JSONObject body = new JSONObject();
body.put("content", text);
body.put("version", version);
body.put("scene", req.getScene());
body.put("openid", req.getOpenid().trim());
if (req.getTitle() != null && !req.getTitle().isEmpty()) {
body.put("title", req.getTitle());
}
if (req.getNickname() != null && !req.getNickname().isEmpty()) {
body.put("nickname", req.getNickname());
}
if (req.getSignature() != null && !req.getSignature().isEmpty()) {
body.put("signature", req.getSignature());
}
JSONObject wx = wxaOpenApiUtils.postJson("/wxa/msg_sec_check", body);
res.setCode("success");
res.setMsg("ok");
res.setObj(wx);
return String.valueOf(JSONObject.fromObject(res));
} catch (Exception e) {
res.setCode("fail");
res.setMsg("调用失败:" + e.getMessage());
return String.valueOf(JSONObject.fromObject(res));
}
}
wxaOpenApiUtils.java
java
/**
* 小程序服务端调用微信开放接口(非米大师 xpay),共用 {@link XpayUtils#getAccessToken()}。
*/
@Component
public class WxaOpenApiUtils {
private final RestTemplate restTemplate = new RestTemplate();
@Autowired
private XpayUtils xpayUtils;
/**
* POST JSON 到 api.weixin.qq.com 指定路径(不含域名)
*
* @param wxPath 如 {@code /wxa/msg_sec_check}
* @param body JSON 请求体
* @return 微信返回的 JSON
*/
public JSONObject postJson(String wxPath, JSONObject body) throws Exception {
String token = xpayUtils.getAccessToken();
String url = "https://api.weixin.qq.com" + wxPath + "?access_token=" + token;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(body.toString(), headers);
String raw = restTemplate.postForObject(url, entity, String.class);
return JSONObject.fromObject(raw);
}
}
综合结果可以看下面官方提供的信息,来判断是否违规
Res.result Object Payload
综合结果
| 参数名 | 类型 | 说明 |
|---|---|---|
| suggest | string | 建议,有risky、pass、review三种值 |
| label | number | 命中标签枚举值,100 正常;10001 广告;20001 时政;20002 色情;20003 辱骂;20006 违法犯罪;20008 欺诈;20012 低俗;20013 版权;21000 其他 |