background
An exception occurs in the online interface, and the abnormal problem cannot be reproduced in both the test environment and the local environment.
technology stack
Front-end umi + antd, back-end egg + egg-sequelize, the main troubleshooting direction is the back-end.
Start troubleshooting
Start troubleshooting the exception, and the exception interface returns no detailed error information. The error message returned is only a simple error prompt 其他异常
, which is the default prompt for interface exceptions.
EXCEPTION_MSG : 'Other exceptions'
However, when the interface is abnormal, specific exception information will be passed in, but it becomes the default value in the front end. It can be seen that one is passed in here undefined
.
try { ...code } catch (e) { return ctx. EXCEPTION (e && e. toString ()) }
After investigation, it was found that the corresponding error content try catch
was not returned in one of the exceptions in the logic processing , resulting in the default value being returned to the front end.reject
return new Promise ( async (resolve, reject) => { try { ...code } catch (error) { -reject ( ) + reject (error) } })
After processing, an error exception message appears, indicating that the regular expression is invalid. According to the source of the error prompt, the corresponding business code function is found, but no regular expression-related code is used in this function.
SyntaxError : Invalid regular expression : /^:(?<name>[a-z_][0-9a-z_]*)(?:\)|,|$|\s|::|;|])/ : Invalid group at injectReplacements ( /opt/ web/node/xxx/node_modules/sequelize/lib/utils/sql. js : 120 : 37 ) at Sequelize . query ( /opt/ web/node/xxx/node_modules/sequelize/lib/sequelize. js : 282 : 13 ) at Promise ( /opt/ web/node/xxx/app/service/sentry/xxx. js : 628 : 45 ) at new Promise (<anonymous>) ...
Because this function calls other business functions, the code that caused the exception can be found out through log printing as follows. Here is a sql
query. Because the order of the query fields needs to be consistent with the returned list, it is used replacements
because it is normal in other environments. , to eliminate this syntax problem.
await this . model . query (sql, { replacements : { name : sortList }, type : QueryTypes . SELECT })
Going back to the calling relationship where the exception was thrown above, after calling the business code, it called , in sequence Sequelize.query
. injectReplacements
If an exception occurs, the problem lies injectReplacements
. However, the call Sequelize.query
does not appear when checking the local source code injectReplacements
. The source code only has the following processing for replacements
the configuration, which is a bit strange.
if (options. replacements ) { if ( Array . isArray (options. replacements )) { sql = Utils . format ([sql]. concat (options. replacements ), this . options . dialect ); } else { sql = Utils . formatNamedParameters (sql, options . replacements , this . options . dialect ); } }
Since the local code cannot be found, then go and search the source code on the server. As expected, the source code on the server is actually inconsistent.
if (options.replacements ) { sql = injectReplacements (sql, this . dialect , options. replacements ); }
injectReplacements
The following regular rules were finally called in the function, which is the exception prompt content at the beginning of this article, indicating that the regular rules are invalid.
const match = remainingString. match ( /^:(?<name>[a-z_][0-9a-z_]*)(?:\)|,|$|\s|::|;|])/ i ); const replacementName = (_d = match == null ? void 0 : match. groups ) == null ? void 0 : _d. name ; if (!replacementName) { continue ; }
Then I checked sequelize
the version numbers of the two environment dependency packages respectively. The local environment is sequelize@6.16.1
, and the actual installed version of the online environment is sequelize@6.21.3
.
"_from" : "sequelize@^6.0.0" , "_id" : "sequelize@6.21.3" ,
Since it is a version issue, unify the version number and see if it can be reproduced locally. Because this dependency is not a direct dependency package, the version cannot be directly locked, so delete the local version first node_modules
and package-lock.json
then reinstall it. The final installed version number is consistent with the server , both sequelize@6.21.3
, but the local operation is normal at this time. 🤷♀️
But why does such a problem occur? Wasn’t it always fine before? The reason is that the dependent sequelize
version number is not locked and sequelize
has been continuously upgraded from the beginning of the project to the present. After checking the official website github
, it was found that due to an sql
injection problem, 6.19.2
this problem has been fixed since the version. As a result, the regular problem cannot be recognized in older node
versions and exceptions occur. github issue address: https://github.com/sequelize/…
solve
This problem can be solved in two ways, because the dependent package where the exception occurs is not a direct dependent package, and the corresponding version number cannot be written directly. Then you can modify package-lock
the version number of the dependent package in the file, but this method is not stable. Later installation will still be overwritten. The second way is to upgrade node
the version. Because the company has many internal server projects, it requires a certain degree of test regression coverage, which involves certain risks and costs.
at last
This article ends here. Two conclusions can be drawn from this troubleshooting of online problems. Interface exceptions do not return specific error messages. You need to pay attention to code problems in the future to improve the efficiency of solving exceptions. When troubleshooting, you must ensure a copy of the code while also ensuring the consistency of system versions and dependency versions in different environments. For dependencies The version number of the package is locked as much as possible to avoid unknown risks caused by automatic upgrades.