问题出现过程
切换新的服务器之后,使用PyExecJS库报错
...
ctx = execjs.compile(js_str)
version_obj = ctx.eval('exportObj')
报错内容:
UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 21-22: invalid continuation byte
排查踩坑过程
根据报错大概可以猜测是编码解析异常,于是网上搜索+ChatGPT搜索查询原因,进行排查调试:
-
首先当然是“控制变量法”,原服务器是一切正常的,为什么切换新服务器就报错了呢?
但是检查系统环境和软件环境,安装的linux版本、python版本、依赖包的版本都与旧服务器完全一致,是不是有“玄学”?? -
项目里的使用方式是读取js文件再用execjs解析,怀疑是不是读取文件的方式有问题,于是将原先的
r
方式改为rb
再解码,没有任何效果; -
根据报错还不知道具体是那个字符解析出错,反复换了几个js文件之后仍然没有作用,于是排除变量,排除django项目、读取文件等因素的影响,直接在python命令行对字符串解析,最终发现还是报错,但是定位到原因是中文字符无法解析;
-
类似的中文字符解析问题之前有遇到过,在windows上会出现
UnicodeDecodeError: 'GBK' codec
错误,需要修改原生的subprocess.py文件解决,或者采用如下方式,于是进行尝试,但是无效;# 创建一个新的 Popen 类,并继承自 subprocess.Popen class MySubprocessPopen(subprocess.Popen): def __init__(self, *args, **kwargs): # 在调用父类(即 subprocess.Popen)的构造方法时,将 encoding 参数直接置为 UTF-8 编码格式 super().__init__(encoding='UTF-8', *args, **kwargs) # 必须要在导入 PyExecJS 模块前,就将 subprocess.Popen 类重置为新的类 subprocess.Popen = MySubprocessPopen
ps: 上述代码忘了是在哪篇文章看到的了,比修改原生文件的方式好,记下来备用。
-
指定execjs的运行环境:
os.environ["EXECJS_RUNTIME"] = "JScript"
os.environ["EXECJS_RUNTIME"] = "Node"
加上相关代码后仍然无效(其实这个才是关键,后面会讲)
-
python3的编码问题,在py文件开头加上# -- coding: utf-8 --,或者尝试对字符串编码再解码等,都无效;
-
还有一系列绞尽脑汁的重装python,升级python版本等无效操作...
最终解决方案
尝试了无数方案后,复盘代码,发现可能还是运行execjs导致的问题,偶然间在一个网页上找到execjs.get().name
可以获取执行环境,于是再试试:
>>> import execjs
>>> execjs.get().name
'SpiderMonkey'
>>> import os
>>> os.environ["EXECJS_RUNTIME"] = "Node"
>>> execjs.get().name
'SpiderMonkey'
>>> os.environ["EXECJS_RUNTIME"] = "JScript"
>>> execjs.get().name
'SpiderMonkey'
发现没有?在执行os.environ["EXECJS_RUNTIME"] = "xxx"
前后运行环境不会有任何改变,这是什么原因呢?
再在旧服务器上执行execjs.get().name
,结果得到的环境是'Node.js (V8)'
噢,因为新服务器没有使用到node环境,所以没有安装nodejs,这就是那个“变量”?
于是在新服务器上安装同版本nodejs,执行成功,大功告成!
- UnicodeDecodeError continuation 纪实 39 positionunicodedecodeerror continuation纪实39 unicodedecodeerror continuation position invalid unicodedecodeerror multibyte 39 position unicodedecodeerror byte 39 position unicodedecodeerror 39 position ordinal unicodedecodeerror 39 position multibyt unicodedecodeerror unexpected 39 position unicodedecodeerror 39 position invalid unicodedecodeerror byte continuation xxx 39 position decode codec