background

An exception occurs on the online interface, and the abnormality 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 investigating

Start troubleshooting, 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: '其他异常'

However, when the interface is abnormal, specific exception information will be passed in, but it becomes the default value at the front end. It can be seen that a undefined is passed in here.

 try {
  ...code
} catch (e) {
  return ctx.EXCEPTION(e && e.toString())
}

After investigation, one of the logical processing try catch did not return the corresponding error content in reject when it was abnormal, resulting in the default value when it was finally returned to the front end.

 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 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 there are other business functions that are called in this function, the code that finds out the exception by printing the log is as follows, here is a sql query, because the order of the query fields needs to be consistent with the returned list, use replacements , because other environments are normal, this syntax problem is excluded.

 await this.model.query(sql, {
  replacements: { name: sortList },
  type: QueryTypes.SELECT
})

Going back to the calling relationship that throws an exception above, after calling the business code, it calls Sequelize.query , injectReplacements , if an exception occurs, the problem lies in injectReplacements . But check the local Sequelize.query source code does not appear injectReplacements call, the source code for replacements configuration will only have the following processing, 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 to the source code on the server to find it, and as expected, the source code on the server is actually inconsistent.

 if (options.replacements) {
  sql = injectReplacements(sql, this.dialect, options.replacements);
}

injectReplacements The following regularity is finally called in the function, which is the content of the exception prompt at the beginning of this article, indicating that the regularity is 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 the version numbers of the two environment dependencies sequelize . The local environment is sequelize@6.16.1 , and the actual installation 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 problem, then unify the version number to see if it can be reproduced locally, because this dependency is not a direct dependency package and cannot directly lock the version, so delete the local node_modules and package-lock.json After reinstalling, the version number of the final installation is the same as that of the server, which is sequelize@6.21.3 , but the local operation is normal at this time. 🤷‍♀️

Now the dependency versions are the same, but the running results are different. Then query the difference between the running versions at both ends. After the query, the local node version number v12.22.1 , the server v8.17.0 . The result is self-evident, because the version of the operating system is inconsistent, which leads to the error of regular recognition. It is also found on the Internet that other people have the same problem, node The problem of regular recognition in some versions. By executing the same code on the remote server and the local server respectively, the server node version is v8.17.0 execution exception occurs.

But why is there such a problem, hasn't it been fine before? The reason is that the dependent sequelize does not have a locked version number. From the beginning of the project to the present sequelize has been continuously upgraded. After querying the official github , because there is a sql injection problem, this problem has been fixed since the 6.19.2 version, resulting in an older version of the problem node in the version, an exception occurred. github issue address: https://github.com/sequelize/sequelize/pull/14472

solve

This problem can be solved in two ways, because the dependent package in which the exception occurs is not a direct dependent package and cannot directly write the corresponding version number, then you can modify the version number of the dependent package in the package-lock file, but This method is not stable, and it will still be overwritten in the later installation. The second way is to upgrade the node version. Because there are many projects on the company's internal servers, certain test regression coverage is required, which has certain risks and costs.

at last

This is the end of this article, and two conclusions have been drawn through this investigation of online problems. Interface exceptions do not return specific error information. Follow-up attention should be paid to code problems to improve the resolution efficiency when exceptions occur. When troubleshooting problems, ensure a code and ensure the consistency of system versions and dependency versions in different environments. For dependencies The version of the package is locked to the version number as much as possible to avoid unknown risks caused by automatic upgrades.

Focus on front-end development, share dry goods related to front-end technology, public account: Nancheng Front-end (ID: nanchengfe)


南城FE
2.2k 声望574 粉丝