SOAP UI中Groovy调用AWS CLI操作DynamoDB报错求助
最近我在SOAP UI里用Groovy脚本调用Windows PowerShell执行AWS CLI命令时踩了个坑:scan命令能正常跑,但get-item命令总是报JSON解析错误。先跟大家唠唠背景和问题细节:
问题背景
我需要验证公司API写入DynamoDB的内容是否正确,已经在PowerShell里配置好AWS CLI,直接执行这些命令完全没问题:
aws dynamodb scan --table-name Accounts aws dynamodb get-item --table-name Accounts --key '{"id":{"S":"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a"}}'
但把这些命令放到SOAP UI的Groovy脚本里调用PowerShell时,第二条get-item命令就报错:
Error parsing parameter '--key': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
我用的Groovy执行PowerShell的代码片段是这样的:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; //Get details and Build the command String powerShellCommand = context.expand( '${#TestCase#PowerShellCommand}' ) String command = "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -Command \"${powerShellCommand}\"" // Executing the command Process powerShellProcess = Runtime.getRuntime().exec(command); // Getting the results powerShellProcess.getOutputStream().close(); String line; //----------------------------------------------- //Run query BufferedReader stdout = new BufferedReader(new InputStreamReader( powerShellProcess.getInputStream())); String jsonString = ""; while ((line = stdout.readLine()) != null) { jsonString = jsonString.concat(line); } stdout.close(); //----------------------------------------------- //Error stuff: BufferedReader stderr = new BufferedReader(new InputStreamReader( powerShellProcess.getErrorStream())); while ((line = stderr.readLine()) != null) { log.info(line); } stderr.close(); //----------------------------------------------- log.info(jsonString);
现在生成的最终执行命令是:
powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -Command "aws dynamodb get-item --table-name Platform.Accounts --key '{\"id\":{\"S\":\"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a\"}}'"
我试过各种调整引号和转义的方式,但一直没找到正确的组合,可直接在PowerShell里跑完全正常,就卡在这里了。
问题根源
这个问题核心是多层命令执行时的引号转义冲突:
- Groovy脚本里用双引号包裹PowerShell命令,里面的双引号需要转义成
\" - 但PowerShell执行
-Command参数时,会对传入的字符串再做一次解析,这时候原本的转义会被吃掉,导致JSON里的双引号变成无转义状态,甚至被截断。
另外,你用单引号包裹JSON在PowerShell里是没问题的,但当这个命令被嵌套到Groovy的双引号命令里时,单引号的处理也会出现异常。
解决方案
有三种可靠的方式可以解决这个问题:
方案1:对JSON里的双引号做双重转义
在Groovy里,我们需要把JSON中的双引号转义两次:第一次是给Groovy本身转义(\"),第二次是给PowerShell转义(再加一个反斜杠变成\\")。
修改后的powerShellCommand内容应该是:
aws dynamodb get-item --table-name Platform.Accounts --key "{\\\"id\\\":{\\\"S\\\":\\\"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a\\\"}}"
对应的Groovy里构建命令时,最终生成的执行字符串会让PowerShell解析后拿到正确的JSON:{"id":{"S":"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a"}}。
方案2:用PowerShell Here-String传递命令
PowerShell的Here-String可以避免多层引号转义的麻烦,我们可以把AWS命令放到Here-String里传递:
修改Groovy里的command构建部分:
String powerShellCommand = context.expand( '${#TestCase#PowerShellCommand}' ) // 用Here-String包裹命令,避免转义混乱 String command = "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -Command \"& { $powerShellCommand }\""
然后powerShellCommand里直接用原本在PowerShell里能正常执行的命令即可:
aws dynamodb get-item --table-name Platform.Accounts --key '{"id":{"S":"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a"}}'
Here-String会保留里面的引号格式,PowerShell能正确解析JSON部分。
方案3:把JSON写入文件传入(适合复杂场景)
如果JSON结构比较复杂,转义实在麻烦,可以把JSON内容写到临时文件里,然后用--key file://path/to/key.json的方式调用AWS CLI,完全避免引号问题:
比如创建一个key.json文件,内容是:
{"id":{"S":"3b7e2c4a-f672-4a12-b2bc-7313b60b0a9a"}}
然后PowerShell命令变成:
aws dynamodb get-item --table-name Platform.Accounts --key file://C:/temp/key.json
这种方式适合复杂查询条件,维护起来更方便。
验证小技巧
你可以先在Groovy里把生成的command字符串打印出来,复制到PowerShell里直接执行,看是否报错,这样能快速排查转义是否正确:
log.info("最终执行的命令:" + command)
如果直接在PowerShell里执行打印出来的命令也报错,那说明转义还没做好,继续调整直到命令能正常运行,再放到Groovy里。
内容的提问来源于stack exchange,提问作者saab613

