{"record":{"id":"99ca6cc354644dfd","repo":"Tencent/APIJSON","slug":"method-parser-getmethod","errorCode":null,"errorMessage":"不允许 method = \" + parser.getMethod() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 method 在 \" + Arrays.toString(methods) + \"内 !","messagePattern":"不允许 method = \" \\+ parser\\.getMethod\\(\\) \\+ \" 的请求调用远程函数 \" \\+ fb\\.getMethod\\(\\) \\+ \" ! 必须满足 method 在 \" \\+ Arrays\\.toString\\(methods\\) \\+ \"内 !","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java","lineNumber":438,"sourceCode":"                    \" == false 时不支持远程函数中的脚本形式！如需支持则设置 AbstractFunctionParser.ENABLE_SCRIPT_FUNCTION = true ！\");\n        }\n\n\t\tif (lang != null && SCRIPT_EXECUTOR_MAP.get(lang) == null) {\n\t\t\tthrow new ClassNotFoundException(\"找不到脚本语言 \" + lang + \" 对应的执行引擎！请先依赖相关库并在后端 APIJSONFunctionParser<T, M, L> 中注册！\");\n\t\t}\n\n\t\tint version = row.get(\"version\") != null ? Integer.parseInt(row.get(\"version\").toString()) : 0;\n\t\tif (parser.getVersion() < version) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 version = \" + parser.getVersion() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 version >= \" + version + \" !\");\n\t\t}\n\t\tString tag = (String) row.get(\"tag\");  // TODO 改为 tags，类似 methods 支持多个 tag。或者干脆不要？因为目前非开放请求全都只能后端指定\n\t\tif (tag != null && tag.equals(parser.getTag()) == false) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 tag = \" + parser.getTag() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 tag = \" + tag + \" !\");\n\t\t}\n\t\tString[] methods = StringUtil.split((String) row.get(\"methods\"));\n\t\tList<String> ml = methods == null || methods.length <= 0 ? null : Arrays.asList(methods);\n\t\tif (ml != null && ml.contains(parser.getMethod().toString()) == false) {\n\t\t\tthrow new UnsupportedOperationException(\"不允许 method = \" + parser.getMethod() + \" 的请求调用远程函数 \" + fb.getMethod() + \" ! 必须满足 method 在 \" + Arrays.toString(methods) + \"内 !\");\n\t\t}\n\n\t\ttry {\n            return invoke(parser, fb.getMethod(), fb.getTypes(), fb.getValues(), (String) row.get(\"returnType\"), current, SCRIPT_EXECUTOR_MAP.get(lang));\n\t\t}\n        catch (Exception e) {\n\t\t\tif (e instanceof NoSuchMethodException) {\n\t\t\t\tthrow new IllegalArgumentException(\"字符 \" + function + \" 对应的远程函数 \" + getFunction(fb.getMethod(), fb.getKeys())\n                        + \" 不在后端 \" + parser.getClass().getName() + \" 内，也不在父类中！如果需要则先新增对应方法！\"\n\t\t\t\t\t\t+ \"\\n请检查函数名和参数数量是否与已定义的函数一致！\"\n\t\t\t\t\t\t+ \"\\n且必须为 function(key0,key1,...) 这种单函数格式！\"\n\t\t\t\t\t\t+ \"\\nfunction 必须符合 Java 函数命名，key 是用于在 curObj 内取值的键！\"\n\t\t\t\t\t\t+ \"\\n调用时不要有空格！\" + (Log.DEBUG ? e.getMessage() : \"\"));\n\t\t\t}\n\t\t\tif (e instanceof InvocationTargetException) {\n\t\t\t\tThrowable te = ((InvocationTargetException) e).getTargetException();\n\t\t\t\tif (StringUtil.isEmpty(te.getMessage(), true) == false) { //到处把函数声明throws Exception改成throws Throwable挺麻烦\n\t\t\t\t\tthrow te instanceof Exception ? (Exception) te : new Exception(te.getMessage());","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractFunctionParser.java#L420-L456","documentation":"Function rows may restrict which HTTP request methods (GET/POST/...) may invoke them via a comma-separated methods column. The parser checks parser.getMethod() against that list and throws UnsupportedOperationException when, for example, a write-only function is invoked from a GET request.","triggerScenarios":"Function row methods='POST' but the request is a GET containing the function call; or methods list omits the method used by the current request.","commonSituations":"Reusing a function expression in a query endpoint when it was registered only for POST; Function rows copied from a demo with restrictive methods; client switched endpoint method from POST to GET.","solutions":["Call the function from an allowed method: change the request to POST (or GET) as the Function row specifies.","Or add the needed method to the Function row's methods column.","Keep function usage aligned with endpoint semantics when designing methods lists."],"exampleFix":"-- before: methods='POST', sent via GET\nUPDATE sys.Function SET methods='GET,POST' WHERE name='enc';\n-- or send the request as POST instead of GET","handlingStrategy":"validation","validationCode":"String[] methods = StringUtil.split((String) functionRow.get(\"methods\"));\nList<String> allowed = methods == null ? null : Arrays.asList(methods);\nif (allowed != null && !allowed.contains(requestMethod.name())) {\n    // use an allowed HTTP method or extend the row's methods list\n}","typeGuard":null,"tryCatchPattern":"try { parser.invoke(fn, current); } catch (UnsupportedOperationException e) { if (e.getMessage().contains(\"method\")) { /* switch endpoint method or update row */ } throw e; }","preventionTips":["Designate each function as read or write and set methods accordingly, then call it only from matching endpoints.","Review methods columns when adding new function-based columns to existing endpoints.","Keep a client-side map of function -> allowed methods."],"tags":["apijson","remote-function","http-method","authorization"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}