Skip to content

Commit c397c82

Browse files
committed
优化报错提示,引导用户自行解决及提交问题;解决 AbstractVerifier.verifyAccess 只允许 Number 类型的 id,并优化变量名;
1 parent 914e22d commit c397c82

File tree

3 files changed

+107
-42
lines changed

3 files changed

+107
-42
lines changed

APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ else if (sqlConfig.isClickHouse()) {
313313
e.getMessage()
314314
+ " " + Log.KEY_SYSTEM_INFO_DIVIDER + " \n**环境信息** "
315315
+ "\n系统: " + System.getProperty("os.name") + " " + System.getProperty("os.version")
316-
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
317316
+ "\n数据库: " + db + " " + sqlConfig.getDBVersion()
317+
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
318318
+ "\nAPIJSON: " + Log.VERSION
319319
);
320320
} catch (Throwable e2) {}

APIJSONORM/src/main/java/apijson/orm/AbstractParser.java

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import static apijson.RequestMethod.GET;
1010

1111
import java.io.UnsupportedEncodingException;
12+
import java.lang.management.ManagementFactory;
13+
import java.net.InetAddress;
1214
import java.net.URLEncoder;
1315
import java.sql.Connection;
1416
import java.sql.SQLException;
@@ -26,6 +28,9 @@
2628
import java.util.concurrent.TimeoutException;
2729

2830
import javax.activation.UnsupportedDataTypeException;
31+
import javax.management.MBeanServer;
32+
import javax.management.ObjectName;
33+
import javax.management.Query;
2934

3035
import com.alibaba.fastjson.JSONArray;
3136
import com.alibaba.fastjson.JSONObject;
@@ -153,6 +158,15 @@ public AbstractParser<T> setTag(String tag) {
153158
return this;
154159
}
155160

161+
protected String requestURL;
162+
public String getRequestURL() {
163+
return requestURL;
164+
}
165+
public AbstractParser<T> setRequestURL(String requestURL) {
166+
this.requestURL = requestURL;
167+
return this;
168+
}
169+
156170
protected JSONObject requestObject;
157171
@Override
158172
public JSONObject getRequest() {
@@ -354,7 +368,7 @@ public JSONObject parseResponse(JSONObject request) {
354368
onVerifyContent();
355369
}
356370
} catch (Exception e) {
357-
return extendErrorResult(requestObject, e);
371+
return extendErrorResult(requestObject, e, requestMethod, getRequestURL());
358372
}
359373
}
360374

@@ -364,7 +378,7 @@ public JSONObject parseResponse(JSONObject request) {
364378
setGlobleRole(requestObject.getString(JSONRequest.KEY_ROLE));
365379
requestObject.remove(JSONRequest.KEY_ROLE);
366380
} catch (Exception e) {
367-
return extendErrorResult(requestObject, e);
381+
return extendErrorResult(requestObject, e, requestMethod, getRequestURL());
368382
}
369383
}
370384

@@ -383,7 +397,7 @@ public JSONObject parseResponse(JSONObject request) {
383397
requestObject.remove(JSONRequest.KEY_EXPLAIN);
384398
requestObject.remove(JSONRequest.KEY_CACHE);
385399
} catch (Exception e) {
386-
return extendErrorResult(requestObject, e);
400+
return extendErrorResult(requestObject, e, requestMethod, getRequestURL());
387401
}
388402

389403
final String requestString = JSON.toJSONString(request);//request传进去解析后已经变了
@@ -407,7 +421,7 @@ public JSONObject parseResponse(JSONObject request) {
407421
onRollback();
408422
}
409423

410-
requestObject = error == null ? extendSuccessResult(requestObject) : extendErrorResult(requestObject, error);
424+
requestObject = error == null ? extendSuccessResult(requestObject) : extendErrorResult(requestObject, error, requestMethod, getRequestURL());
411425

412426
JSONObject res = (globleFormat != null && globleFormat) && JSONResponse.isSuccess(requestObject) ? new JSONResponse(requestObject) : requestObject;
413427

@@ -608,8 +622,9 @@ public static JSONObject extendResult(JSONObject object, int code, String msg) {
608622
if (object == null) {
609623
object = new JSONObject(true);
610624
}
625+
boolean isOk = JSONResponse.isSuccess(code);
611626
if (object.containsKey(JSONResponse.KEY_OK) == false) {
612-
object.put(JSONResponse.KEY_OK, JSONResponse.isSuccess(code));
627+
object.put(JSONResponse.KEY_OK, isOk);
613628
}
614629
if (object.containsKey(JSONResponse.KEY_CODE) == false) {
615630
object.put(JSONResponse.KEY_CODE, code);
@@ -619,6 +634,7 @@ public static JSONObject extendResult(JSONObject object, int code, String msg) {
619634
if (m.isEmpty() == false) {
620635
msg = m + " ;\n " + StringUtil.getString(msg);
621636
}
637+
622638
object.put(JSONResponse.KEY_MSG, msg);
623639
return object;
624640
}
@@ -642,36 +658,84 @@ public static JSONObject newSuccessResult() {
642658
* @return
643659
*/
644660
public static JSONObject extendErrorResult(JSONObject object, Exception e) {
661+
return extendErrorResult(object, e, null, null);
662+
}
663+
/**添加请求成功的状态内容
664+
* @param object
665+
* @return
666+
*/
667+
public static JSONObject extendErrorResult(JSONObject object, Exception e, RequestMethod requestMethod, String url) {
645668
String msg = e.getMessage();
646-
669+
647670
if (Log.DEBUG) {
648671
try {
649672
int index = msg.lastIndexOf(Log.KEY_SYSTEM_INFO_DIVIDER);
650673
String info = index >= 0 ? msg.substring(index + Log.KEY_SYSTEM_INFO_DIVIDER.length()).trim()
651674
: "\n**环境信息** "
652675
+ "\n系统: " + System.getProperty("os.name") + " " + System.getProperty("os.version")
653-
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
654676
+ "\n数据库: <!-- 请填写,例如 MySQL 5.7 -->"
677+
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
655678
+ "\nAPIJSON: " + Log.VERSION;
656679

657680
msg = index < 0 ? msg : msg.substring(0, index).trim();
658681
String encodedMsg = URLEncoder.encode(msg, "UTF-8");
682+
683+
if (StringUtil.isEmpty(url, true)) {
684+
String host = "localhost";
685+
try {
686+
host = InetAddress.getLocalHost().getHostAddress();
687+
} catch (Throwable e2) {}
688+
689+
String port = "8080";
690+
try {
691+
MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
692+
693+
Set<ObjectName> objectNames = beanServer.queryNames(
694+
new ObjectName("*:type=Connector,*"),
695+
Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"))
696+
);
697+
String p = objectNames.iterator().next().getKeyProperty("port");
698+
port = StringUtil.isEmpty(p, true) ? port : p;
699+
} catch (Throwable e2) {}
700+
701+
url = "http://" + host + ":" + port + "/" + (requestMethod == null ? RequestMethod.GET : requestMethod).name().toLowerCase();
702+
}
703+
704+
String req = JSON.toJSONString(object);
705+
try {
706+
req = URLEncoder.encode(req, "UTF-8");
707+
} catch (Throwable e2) {}
708+
709+
710+
boolean isSQLException = e instanceof SQLException; // SQL 报错一般都是通用问题,优先搜索引擎
711+
String apiatuoAndGitHubLink = "\n【APIAuto】: \n http://apijson.cn/api?type=JSON&url=" + URLEncoder.encode(url, "UTF-8") + "&json=" + req
712+
+ " \n\n【GitHub】: \n https://www.google.com/search?q=site%3Agithub.com%2FTencent%2FAPIJSON+++" + encodedMsg;
659713

660-
msg += " \n\n\n浏览器打开以下链接搜索答案\nGitHub: https://github.com/Tencent/APIJSON/issues?q=is%3Aissue+" + encodedMsg
661-
+ " \n\nGoogle:https://www.google.com/search?q=" + encodedMsg
662-
+ " \n\nBaidu:https://www.baidu.com/s?ie=UTF-8&wd=" + encodedMsg
663-
+ " \n\n都没找到答案?打开这个链接 https://github.com/Tencent/APIJSON/issues/new?assignees=&labels=&template=--bug.md "
714+
msg += " \n\n\n浏览器打开以下链接查看解答"
715+
+ (isSQLException ? "" : apiatuoAndGitHubLink)
716+
// GitHub Issue 搜索貌似是精准包含,不易找到答案 + " \n\nGitHub: \n https://github.com/Tencent/APIJSON/issues?q=is%3Aissue+" + encodedMsg
717+
+ " \n\n【Google】:\n https://www.google.com/search?q=" + encodedMsg
718+
+ " \n\n【百度】:\n https://www.baidu.com/s?ie=UTF-8&wd=" + encodedMsg
719+
+ (isSQLException ? apiatuoAndGitHubLink : "")
720+
+ " \n\n都没找到答案?打开这个链接 \n https://github.com/Tencent/APIJSON/issues/new?assignees=&labels=&template=--bug.md "
664721
+ "\n然后提交问题,推荐用以下模板修改,注意要换行保持清晰可读。"
665722
+ "\n【标题】:" + msg
666-
+ "\n【内容】:" + info + "\n\n**问题描述**\n" + msg;
667-
} catch (Throwable e2) {
668-
e2.printStackTrace();
669-
}
723+
+ "\n【内容】:" + info + "\n\n**问题描述**\n" + msg
724+
+ "\n\n<!-- 尽量完整截屏(至少包含请求和回包结果,还可以加上控制台报错日志),然后复制粘贴到这里 -->"
725+
+ "\n\nPOST " + url
726+
+ "\n请求 Request JSON:\n ```js"
727+
+ "\n 请填写,例如 { \"Users\":{} }"
728+
+ "\n```"
729+
+ "\n\n返回结果 Response JSON:\n ```js"
730+
+ "\n 请填写,例如 { \"Users\": {}, \"code\": 401, \"msg\": \"Users 不允许 UNKNOWN 用户的 GET 请求!\" }"
731+
+ "\n```";
732+
} catch (Throwable e2) {}
670733
}
671-
734+
672735
JSONObject error = newErrorResult(e);
673736
return extendResult(object, error.getIntValue(JSONResponse.KEY_CODE), msg);
674737
}
738+
675739
/**新建错误状态内容
676740
* @param e
677741
* @return
@@ -1000,7 +1064,7 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
10001064
//不能改变,因为后面可能继续用到,导致1以上都改变 []:{0:{Comment[]:{0:{Comment:{}},1:{...},...}},1:{...},...}
10011065
final String query = request.getString(JSONRequest.KEY_QUERY);
10021066
final Integer count = request.getInteger(JSONRequest.KEY_COUNT); //TODO 如果不想用默认数量可以改成 getIntValue(JSONRequest.KEY_COUNT);
1003-
final int page = request.getIntValue(JSONRequest.KEY_PAGE);
1067+
final Integer page = request.getInteger(JSONRequest.KEY_PAGE);
10041068
final Object join = request.get(JSONRequest.KEY_JOIN);
10051069

10061070
int query2;
@@ -1026,8 +1090,9 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
10261090
}
10271091
}
10281092

1093+
int page2 = page == null ? 0 : page;
10291094
int maxPage = getMaxQueryPage();
1030-
if (page < 0 || page > maxPage) {
1095+
if (page2 < 0 || page2 > maxPage) {
10311096
throw new IllegalArgumentException(path + "/" + JSONRequest.KEY_PAGE + ":value 中 value 的值不合法!必须在 0-" + maxPage + " 内 !");
10321097
}
10331098

@@ -1052,8 +1117,8 @@ public JSONArray onArrayParse(JSONObject request, String parentPath, String name
10521117

10531118
JSONArray response = null;
10541119
try {
1055-
int size = count2 == 0 ? max : count2;//count为每页数量,size为第page页实际数量,max(size) = count
1056-
Log.d(TAG, "onArrayParse size = " + size + "; page = " + page);
1120+
int size = count2 == 0 ? max : count2; //count为每页数量,size为第page页实际数量,max(size) = count
1121+
Log.d(TAG, "onArrayParse size = " + size + "; page = " + page2);
10571122

10581123

10591124
//key[]:{Table:{}}中key equals Table时 提取Table
@@ -1076,13 +1141,13 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
10761141
SQLConfig config = createSQLConfig()
10771142
.setMethod(requestMethod)
10781143
.setCount(size)
1079-
.setPage(page)
1144+
.setPage(page2)
10801145
.setQuery(query2)
10811146
.setTable(arrTableKey)
10821147
.setJoinList(onJoinParse(join, request));
10831148

10841149
JSONObject parent;
1085-
1150+
10861151
boolean isExtract = true;
10871152

10881153
//生成size个
@@ -1091,7 +1156,7 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
10911156
if (parent == null || parent.isEmpty()) {
10921157
break;
10931158
}
1094-
1159+
10951160
long startTime = System.currentTimeMillis();
10961161

10971162
/* 这里优化了 Table[]: { Table:{} } 这种情况下的性能
@@ -1101,13 +1166,13 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
11011166
JSONObject fo = i != 0 || arrTableKey == null ? null : parent.getJSONObject(arrTableKey);
11021167
@SuppressWarnings("unchecked")
11031168
List<JSONObject> list = fo == null ? null : (List<JSONObject>) fo.remove(SQLExecutor.KEY_RAW_LIST);
1104-
1169+
11051170
if (list != null && list.isEmpty() == false) {
11061171
isExtract = false;
1107-
1172+
11081173
list.set(0, fo); // 不知道为啥第 0 项也加了 @RAW@LIST
11091174
response.addAll(list); // List<JSONObject> cannot match List<Object> response = new JSONArray(list);
1110-
1175+
11111176
long endTime = System.currentTimeMillis(); // 0ms
11121177
Log.d(TAG, "\n onArrayParse <<<<<<<<<<<<<<<<<<<<<<<<<<<<\n for (int i = 0; i < (isSubquery ? 1 : size); i++) "
11131178
+ " startTime = " + startTime + "; endTime = " + endTime + "; duration = " + (endTime - startTime) + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
@@ -1117,7 +1182,7 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
11171182
//key[]:{Table:{}}中key equals Table时 提取Table
11181183
response.add(getValue(parent, childKeys)); //null有意义
11191184
}
1120-
1185+
11211186
//Table>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
11221187

11231188

@@ -1143,7 +1208,7 @@ else if (childKeys.length == 1 && JSONRequest.isTableKey(childKeys[0])) { //
11431208
if (fo instanceof Boolean || fo instanceof Number || fo instanceof String) { //[{}] 和 [[]] 都没意义
11441209
putQueryResult(path, response);
11451210
}
1146-
1211+
11471212
long endTime = System.currentTimeMillis();
11481213
Log.d(TAG, "\n onArrayParse <<<<<<<<<<<<<<<<<<<<<<<<<<<<\n isExtract >> putQueryResult "
11491214
+ " startTime = " + startTime + "; endTime = " + endTime + "; duration = " + (endTime - startTime) + "\n >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
@@ -1739,13 +1804,13 @@ else if (config.isClickHouse()) {
17391804
e.getMessage()
17401805
+ " " + Log.KEY_SYSTEM_INFO_DIVIDER + " \n**环境信息** "
17411806
+ "\n系统: " + System.getProperty("os.name") + " " + System.getProperty("os.version")
1742-
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
17431807
+ "\n数据库: " + db + " " + config.getDBVersion()
1808+
+ "\nJDK: " + System.getProperty("java.version") + " " + System.getProperty("os.arch")
17441809
+ "\nAPIJSON: " + Log.VERSION
17451810
);
17461811
} catch (Throwable e2) {}
17471812
}
1748-
1813+
17491814
if (Log.DEBUG == false && e instanceof SQLException) {
17501815
throw new SQLException("数据库驱动执行异常SQLException,非 Log.DEBUG 模式下不显示详情,避免泄漏真实模式名、表名等隐私信息", e);
17511816
}

APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
268268

269269
//验证角色,假定真实强制匹配<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
270270

271-
String visitorIdkey = getVisitorIdKey(config);
271+
String visitorIdKey = getVisitorIdKey(config);
272272

273273
Object requestId;
274274
switch (role) {
@@ -285,9 +285,9 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
285285
}
286286

287287
//key!{}:[] 或 其它没有明确id的条件 等 可以和key{}:list组合。类型错误就报错
288-
requestId = (Number) config.getWhere(visitorIdkey, true);//JSON里数值不能保证是Long,可能是Integer
288+
requestId = config.getWhere(visitorIdKey, true);//JSON里数值不能保证是Long,可能是Integer
289289
@SuppressWarnings("unchecked")
290-
Collection<Object> requestIdArray = (Collection<Object>) config.getWhere(visitorIdkey + "{}", true);//不能是 &{}, |{} 不要传,直接{}
290+
Collection<Object> requestIdArray = (Collection<Object>) config.getWhere(visitorIdKey + "{}", true);//不能是 &{}, |{} 不要传,直接{}
291291
if (requestId != null) {
292292
if (requestIdArray == null) {
293293
requestIdArray = new JSONArray();
@@ -296,7 +296,7 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
296296
}
297297

298298
if (requestIdArray == null) {//可能是@得到 || requestIdArray.isEmpty()) {//请求未声明key:id或key{}:[...]条件,自动补全
299-
config.putWhere(visitorIdkey+"{}", JSON.parseArray(list), true); //key{}:[]有效,SQLConfig里throw NotExistException
299+
config.putWhere(visitorIdKey+"{}", JSON.parseArray(list), true); //key{}:[]有效,SQLConfig里throw NotExistException
300300
}
301301
else {//请求已声明key:id或key{}:[]条件,直接验证
302302
for (Object id : requestIdArray) {
@@ -307,7 +307,7 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
307307
throw new UnsupportedDataTypeException(table + ".id类型错误,id类型必须是Long!");
308308
}
309309
if (list.contains(Long.valueOf("" + id)) == false) {//Integer等转为Long才能正确判断。强转崩溃
310-
throw new IllegalAccessException(visitorIdkey + " = " + id + " 的 " + table
310+
throw new IllegalAccessException(visitorIdKey + " = " + id + " 的 " + table
311311
+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
312312
}
313313
}
@@ -321,20 +321,20 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
321321
throw new IllegalArgumentException("POST 请求必须在Table内设置要保存的 key:value !");
322322
}
323323

324-
int index = c.indexOf(visitorIdkey);
324+
int index = c.indexOf(visitorIdKey);
325325
if (index >= 0) {
326326
Object oid;
327327
for (List<Object> ovl : ovs) {
328328
oid = ovl == null || index >= ovl.size() ? null : ovl.get(index);
329329
if (oid == null || StringUtil.getString(oid).equals("" + visitorId) == false) {
330-
throw new IllegalAccessException(visitorIdkey + " = " + oid + " 的 " + table
330+
throw new IllegalAccessException(visitorIdKey + " = " + oid + " 的 " + table
331331
+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
332332
}
333333
}
334334
}
335335
else {
336336
List<String> nc = new ArrayList<>(c);
337-
nc.add(visitorIdkey);
337+
nc.add(visitorIdKey);
338338
config.setColumn(nc);
339339

340340
List<List<Object>> nvs = new ArrayList<>();
@@ -349,13 +349,13 @@ public boolean verifyAccess(SQLConfig config) throws Exception {
349349
}
350350
}
351351
else {
352-
requestId = config.getWhere(visitorIdkey, true);//JSON里数值不能保证是Long,可能是Integer
352+
requestId = config.getWhere(visitorIdKey, true);//JSON里数值不能保证是Long,可能是Integer
353353
if (requestId != null && StringUtil.getString(requestId).equals(StringUtil.getString(visitorId)) == false) {
354-
throw new IllegalAccessException(visitorIdkey + " = " + requestId + " 的 " + table
354+
throw new IllegalAccessException(visitorIdKey + " = " + requestId + " 的 " + table
355355
+ " 不允许 " + role + " 用户的 " + method.name() + " 请求!");
356356
}
357357

358-
config.putWhere(visitorIdkey, visitorId, true);
358+
config.putWhere(visitorIdKey, visitorId, true);
359359
}
360360
break;
361361
case ADMIN://这里不好做,在特定接口内部判。 可以是 /get/admin + 固定秘钥 Parser#needVerify,之后全局跳过验证

0 commit comments

Comments
 (0)