You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

API Gateway如何根据请求动态返回XML或JSON格式响应?

问题描述

我有一套基于Node.js的API Gateway服务栈和Node Lambda函数,想要实现API Gateway根据请求参数format(取值为xml或json),返回对应Content-Type为application/xml或application/json的响应。试过添加响应模型(response models)但没生效,配置BinaryTypes也没用,现在只能返回单一格式(当前示例始终返回application/json)。想知道这种动态切换响应格式的需求是否可行?还是必须创建两个独立的端点?

Lambda 函数代码

exports.handler = async function(event, context, callback) {
    var format = event.format;

    if (!format) {
        callback(Error("[BadRequest] missing parameters"));
    }

    const promise = new Promise(function(resolve, reject) {
        https
            .get("exampleendpoint.com", (res) => {
                let body = "";

                res.on("data", (chunk) => {
                    body += chunk;
                });

                res.on("end", () => {
                    var results = JSON.parse(body);
                    if (format && format.toUpperCase() === "XML") {
                        var response = {
                            statusCode: 200,
                            headers: {
                                "content-type": "application/xml"
                            },
                            body: '<?xml version="1.0" encoding="UTF-8"?><result>' +
                                OBJtoXML(results) +
                                "</result>",
                        };
                        resolve(response);
                    } else {
                        var response = {
                            statusCode: 200,
                            headers: {
                                "content-type": "application/json"
                            },
                            body: JSON.stringify(results),
                        };
                        resolve(response);
                    }
                });
            })
            .on("error", (e) => {
                var response = {
                    statusCode: 500,
                    body: "",
                    errorMessage: "Error from example.com",
                };
                resolve(response);
            });
    });
    return promise;
};

API Gateway CDK 配置代码

const epqApi = new gateway.RestApi(this, "restApi", {
    restApiName: "resultsApi",
    cloudWatchRole: true,
    description: "Calls the service for the app",
    endpointTypes: [gateway.EndpointType.REGIONAL],
    deployOptions: {
        stageName: "prod",
        loggingLevel: gateway.MethodLoggingLevel.OFF,
        dataTraceEnabled: false,
    },
});

const epqResource = epqApi.root.addResource("v1");

const epqIntegration: gateway.LambdaIntegration =
    new gateway.LambdaIntegration(generatePqsResultFunction, {
        proxy: false,
        allowTestInvoke: true,
        passthroughBehavior: gateway.PassthroughBehavior.NEVER,
        contentHandling: gateway.ContentHandling.CONVERT_TO_TEXT,
        requestTemplates: {
            "application/json": `{ 
                "format":"$input.params('format')"     
            }`,
        },
        integrationResponses: [{
                statusCode: "200",
                responseParameters: {
                    "method.response.header.Access-Control-Allow-Origin": "'*'",
                },
                responseTemplates: {
                    "application/json": "$input.path('$.body')",
                    "application/xml": "$input.path('$.body')",
                },
            },
            {
                statusCode: "400",
                selectionPattern: "^\\[BadRequest\\].*",
                responseParameters: {
                    "method.response.header.Access-Control-Allow-Origin": "'*'",
                },
                responseTemplates: {
                    "application/javascript": "#set($inputRoot = $input.path('$')) {\"errorMessage\" : \"$input.path('$.errorMessage')\"}",
                },
            },
        ],
    });

epqResource.addMethod("GET", epqIntegration, {
    requestParameters: {
        //all params need to be in here, even if they are not required
        "method.request.querystring.x": false,
        "method.request.querystring.y": false,
        "method.request.querystring.units": false,
        "method.request.querystring.format": false,
        "method.request.querystring.wkid": false,
        "method.request.querystring.includeDate": false,
    },
    methodResponses: [
        // Successful response from the integration
        {
            statusCode: "200",
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": true,
            },
        },
        {
            statusCode: "400",
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": true,
            },
        },
    ],
});
解决方案

这个需求完全可行,不需要创建两个独立端点。问题出在API Gateway配置未根据Lambda返回的格式标识动态匹配响应逻辑,以下是两种可行的解决方式:

方式一:优化API Gateway集成配置

关键调整步骤

  1. Lambda返回添加格式标识
    在Lambda的响应对象中新增format字段,方便API Gateway识别返回类型:

    // XML响应示例
    var response = {
        statusCode: 200,
        headers: { "content-type": "application/xml" },
        body: '<?xml version="1.0" encoding="UTF-8"?><result>' + OBJtoXML(results) + "</result>",
        format: "xml"
    };
    
    // JSON响应示例
    var response = {
        statusCode: 200,
        headers: { "content-type": "application/json" },
        body: JSON.stringify(results),
        format: "json"
    };
    
  2. 更新Method Responses配置
    在200状态码中添加允许返回Content-Type头:

    methodResponses: [
        {
            statusCode: "200",
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": true,
                "method.response.header.Content-Type": true // 允许返回Content-Type头
            },
        },
        // 保留400状态码配置
        {
            statusCode: "400",
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": true,
            },
        },
    ]
    
  3. 拆分集成响应规则
    为XML和JSON分别创建集成响应,通过selectionPattern匹配Lambda返回的format字段:

    integrationResponses: [
        // JSON格式响应规则
        {
            statusCode: "200",
            selectionPattern: '"format":"json"',
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": "'*'",
                "method.response.header.Content-Type": "'application/json'"
            },
            responseTemplates: {
                "application/json": "$input.path('$.body')"
            },
        },
        // XML格式响应规则
        {
            statusCode: "200",
            selectionPattern: '"format":"xml"',
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": "'*'",
                "method.response.header.Content-Type": "'application/xml'"
            },
            responseTemplates: {
                "application/xml": "$input.path('$.body')"
            },
        },
        // 保留400错误响应配置
        {
            statusCode: "400",
            selectionPattern: "^\\[BadRequest\\].*",
            responseParameters: {
                "method.response.header.Access-Control-Allow-Origin": "'*'",
            },
            responseTemplates: {
                "application/javascript": "#set($inputRoot = $input.path('$')) {\"errorMessage\" : \"$input.path('$.errorMessage')\"}",
            },
        },
    ]
    

方式二:启用Lambda代理集成(更简单)

直接开启Lambda代理模式,让API Gateway完全透传Lambda返回的响应(包括Headers、Body、StatusCode),无需配置响应模板:

修改集成配置:

const epqIntegration: gateway.LambdaIntegration =
    new gateway.LambdaIntegration(generatePqsResultFunction, {
        proxy: true, // 开启代理模式
        allowTestInvoke: true,
    });

这种模式下,动态切换格式的逻辑完全由Lambda处理,API Gateway不做额外转换,配置更简洁。


内容的提问来源于stack exchange,提问作者Jordan Parfitt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:45:37