跳到主要内容
版本:3.19.0

在 JSON 与 SOAP XML 之间转换

SOAP 服务使用 XML 信封交换数据,但许多 HTTP 客户端使用 JSON。body-transformer 插件可以解码 JSON 请求、渲染 SOAP 信封、解析 XML 响应,并向客户端返回 JSON 文档。

本指南使用示例国家信息服务配置双向转换。


APISIX 将 JSON 请求转换为 SOAP XML,并将 XML 响应转换为 JSON 的流程

前置条件​

  • 安装 Docker。
  • 安装 cURL,用于向 APISIX 发送请求进行验证。
  • 安装 Git,用于下载示例 SOAP 服务。
  • 按照快速入门教程在 Docker 中启动 APISIX。以下命令使用该教程创建的 apisix-quickstart-net 网络。
  • 如果启用了 Admin API 身份认证,请将管理员角色的密钥导出为 ADMIN_API_KEY。Docker 快速入门为了便于本地评估而禁用了身份认证;生产环境中请保持启用。

部署示例 SOAP 服务​

克隆 Spring 示例服务,并检出本指南验证过的修订版本:

git clone "https://github.com/spring-guides/gs-producing-web-service.git"
cd gs-producing-web-service/complete
git switch --detach c9c88ea61cfbcef0de6275c7b6c8b1320549017a

在与 APISIX 相同的 Docker 网络中运行服务。命名卷会在容器重启后保留 Maven 依赖缓存:

docker volume create soap-maven-cache
docker rm -f quickstart-soap-service 2>/dev/null || true

docker run -d \
--rm \
--name quickstart-soap-service \
--network apisix-quickstart-net \
-v "$PWD:/workspace" \
-v soap-maven-cache:/root/.m2 \
-w /workspace \
eclipse-temurin:17-jdk@sha256:420933bf319e6aff4bec22eff8d2a31c824df5d853432e3dc0f46d6ea8dd5919 \
./mvnw spring-boot:run

持续查看启动日志:

docker logs -f quickstart-soap-service

等待日志中出现 Started ProducingWebServiceApplication,然后按 Ctrl+C。应用会继续在后台运行。

创建转换模板​

创建请求模板。该模板从解码后的 JSON 正文中读取 name,并渲染示例服务所需的 SOAP 请求:

request-template.xml
cat > request-template.xml <<'EOF'
<?xml version="1.0"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:getCountryRequest xmlns:ns0="https://spring.io/guides/gs-producing-web-service">
<ns0:name>{{_escape_xml(name)}}</ns0:name>
</ns0:getCountryRequest>
</soap-env:Body>
</soap-env:Envelope>
EOF

创建响应模板。插件在向模板公开响应字段前,会先移除 XML 命名空间前缀:

response-template.json
cat > response-template.json <<'EOF'
{% if Envelope.Body.Fault == nil then %}
{
"status":"{{_ctx.var.status}}",
"currency":"{{Envelope.Body.getCountryResponse.country.currency}}",
"population":{{Envelope.Body.getCountryResponse.country.population}},
"capital":"{{Envelope.Body.getCountryResponse.country.capital}}",
"name":"{{Envelope.Body.getCountryResponse.country.name}}"
}
{% else %}
{
"message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*},
"code":"{{Envelope.Body.Fault.faultcode}}"
{% if Envelope.Body.Fault.faultactor ~= nil then %}
, "actor":"{{Envelope.Body.Fault.faultactor}}"
{% end %}
}
{% end %}
EOF

对模板进行编码,以便安全地插入 Admin API JSON 文档:

export REQUEST_TEMPLATE_BASE64="$(base64 < request-template.xml | tr -d '\r\n')"
export RESPONSE_TEMPLATE_BASE64="$(base64 < response-template.json | tr -d '\r\n')"

模板使用 lua-resty-template 语法。插件还提供 _escape_xml() 和 _escape_json(),用于根据上下文进行转义;提供 _body 访问原始正文;提供 _ctx 访问请求上下文。

配置 APISIX​

创建启用了 body-transformer 插件的路由:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"id": "body-transformer-route",
"methods": ["POST"],
"uri": "/ws",
"plugins": {
"body-transformer": {
"request": {
"template": "$REQUEST_TEMPLATE_BASE64",
"template_is_base64": true,
"input_format": "json"
},
"response": {
"template": "$RESPONSE_TEMPLATE_BASE64",
"template_is_base64": true,
"input_format": "xml"
}
},
"proxy-rewrite": {
"uri": "/services",
"headers": {
"set": {
"Content-Type": "text/xml"
}
}
},
"response-rewrite": {
"headers": {
"set": {
"Content-Type": "application/json"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"quickstart-soap-service:8080": 1
}
}
}
EOF

❶ 在渲染请求模板前,将客户端请求解码为 JSON。

❷ 在渲染响应模板前,将上游响应解码为 XML。

❸ 将转换后的请求发送到示例服务的 /services 端点,并使用与 SOAP 兼容的内容类型。

❹ 使用 JSON 内容类型返回转换后的响应。

❺ 通过 apisix-quickstart-net 上的容器名称解析示例服务。

验证​

向路由发送 JSON 请求:

curl "http://127.0.0.1:9080/ws" -X POST \
-H "Content-Type: application/json" \
-d '{"name":"Spain"}'

你应收到类似以下的响应:

{
"status": "200",
"currency": "EUR",
"population": 46704314,
"capital": "Madrid",
"name": "Spain"
}

客户端发送和接收 JSON。APISIX 向上游服务发送 SOAP XML 请求,并将其 XML 响应转换回 JSON。

下一步​

body-transformer 插件还可以转换其他受支持的输入格式,或修改请求和响应正文。有关配置选项,请参阅 Plugin Hub 参考文档。