【问题标题】:AWS API Gateway - Integration Response body mappingAWS API Gateway - 集成响应正文映射
【发布时间】:2018-05-02 09:35:33
【问题描述】:

在 AWS API Gateway 集成响应正文映射中,我有以下代码:

#set($inputRoot = $input.path('$.Item'))
[
#foreach($elem in $inputRoot.Events)
 {
  "id": $elem.id,
  "from" : $elem.from,
  "to" : $elem.to,
  "spent" : $elem.spent,
  #if("$!elem.comment" != "")
    "comment": $elem.comment,    
  #end
  "project" : {
    "id" : $elem.project.id,
    "number" : $elem.project.number,
    "name" : $elem.project.name
  }
  }
#if($foreach.hasNext),#end
#end
]

数据来自查询 DynamoDB 表的 lambda 函数

API 网关返回数据如下:

[
 {
  "id": 123443214,
  "from" : 19:34,
  "to" : 22:30,
  "spent" : 02:56,
    "project" : {
    "id" : 4321,
    "number" : CIB,
    "name" : Backend
  }
  }
, {
  "id": 12341234,
  "from" : 19:34,
  "to" : 22:30,
  "spent" : 02:56,
    "project" : {
    "id" : 12341234,
    "number" : CIB,
    "name" : Backend
  }
  }
]

所以它已经格式化了。如何让 APi Gateway 返回未格式化的响应?所以它只是纯 json,没有折线、缩进等?

提前致谢!

【问题讨论】:

    标签: amazon-web-services aws-api-gateway


    【解决方案1】:

    (简短的初步说明:您在 JSON 字符串值周围缺少一些引号)。

    可以使用## 删除换行符,使用#**# 删除缩进,如下所示,但模板看起来有点难看:

    #set($inputRoot = $input.path('$.Item'))##
    [##
    #foreach($elem in $inputRoot.Events)##
    {##
    #**#"id":$elem.id,##
    #**#"from": $elem.from,##
    #**#"to":$elem.to,##
    #**#"spent":$elem.spent,##
    #if("$!elem.comment" != "")##
    #*  *#"comment":$elem.comment,##
    #end##
    #**#"project":{##
    #**#"id":$elem.project.id,##
    #**#"number":"$elem.project.number",##
    #**#"name":"$elem.project.name"##
    }##
    }##
    #if($foreach.hasNext),#end##
    #end##
    ]##
    

    由于缩进一开始在这里的唯一原因是模板的可读性,我会转向另一个方向。

    例如,您可以使用org.json 在您的 View servlet 中添加一个后处理整洁的格式化程序:

    import org.json.JSONObject;
      ....
    Writer writer = new StringWriter();
    getVelocityView().merge(template, context, writer);
    String compactJSON = new JSONObject(writer.toString()).toString();
    response.getWriter().write(compactJSON);
    

    但是这仅适用于小型 JSON 文件,因为响应被缓冲到内存中,所以让我们继续寻找更优雅的解决方案。

    要走的路是预处理您的模板,使用自定义 ResouceLoader。

    CompactJSONResourceLoader.java

    package my.custom.loader;
    
    import java.io.InputStream;
    import java.io.IOException;
    import org.apache.commons.collections.ExtendedProperties;
    import org.apache.velocity.exception.ResourceNotFoundException;
    import org.apache.velocity.runtime.resource.Resource;
    import org.apache.velocity.runtime.resource.loader.ResourceLoader;
    import org.apache.velocity.runtime.resource.loader.ResourceLoaderFactory;
    
    public class CompactJSONResourceLoader extends ResourceLoader
    {
        protected ResourceLoader innerLoader = null;
    
        @Override
        public void init(ExtendedProperties configuration)
        {
            try
            {
                String innerLoaderID = configuration.getString("innerLoader") + ".resource.loader";
                String innerLoaderClass = rsvc.getConfiguration().getString(innerLoaderID + ".class");
                innerLoader = ResourceLoaderFactory.getLoader(rsvc, innerLoaderClass);
                ExtendedProperties innerConfiguration = rsvc.getConfiguration().subset(innerLoaderID);
                innerLoader.commonInit(rsvc, innerConfiguration);
                innerLoader.init(innerConfiguration);
            }
            catch (Exception e)
            {
                log.error("could not initialize CompactJSONResourceLoader inner loader", e);
            }
        }
    
        protected class CompactJSONInputStream extends InputStream
        {
            InputStream innerStream = null;
            boolean insideQuotes = false;
    
            public CompactJSONInputStream(InputStream innerStream)
            {
                this.innerStream = innerStream;
            }
    
            @Override
            public int read() throws IOException
            {
                int ch;
                do
                {
                    ch = innerStream.read();
                    if (insideQuotes)
                    {
                        if (ch == '"') insideQuotes = false;
                        break;
                    }
                    else if (!Character.isWhitespace(ch))
                    {
                        if (ch == '"') insideQuotes = true;
                        break;
                    }
                }
                while (ch != -1);
                return ch;
            }
        }
    
        @Override
        public InputStream getResourceStream(String source) throws ResourceNotFoundException
        {
            return new CompactJSONInputStream(innerLoader.getResourceStream(source));
        }
    
        @Override
        public boolean isSourceModified(Resource resource)
        {
            return innerLoader.isSourceModified(resource);
        }
    
        @Override
        public long getLastModified(Resource resource)
        {
            return innerLoader.getLastModified(resource);
        }
    }
    

    然后您需要使用以下属性配置 Velocity:

    resource.loader = compact
    compact.resource.loader.class = my.custom.loader.CompactJSONResourceLoader
    

    compact.resource.loader.innerLoader = 文件

    (当然,您可以将file 替换为您当前使用的资源加载器)。

    【讨论】:

    • 我要补充一点,建议的自定义 ResourceLoader 用于 Velocity 1.7 API。如果您使用的是 Velocity 2.0,则需要调整源代码,使其直接与 Readers 一起工作,而不是 InputStreams。
    • 感谢您非常详细的回答!我使用 NodeJs,所以这个 ResourceLoader 可能不可用。但是由于我的 JSON 字符串值周围缺少引号,它工作得很好......我自己真是个愚蠢的错误
    • 这个问题可能应该被标记为velocity.js,而不是velocity。但无论如何,这是一个有趣的回答,我很高兴,这是我第一次接受 velocity.js 速度的回答!
    • 如何配置 AWS API Gateway 以使用它?不使用 Lambda 代理集成。
    • @Paya 那你就被丑陋的 cmets 解决方案困住了。
    猜你喜欢
    • 2018-04-15
    • 2018-01-20
    • 2020-04-18
    • 2018-06-09
    • 2017-11-30
    • 2016-12-15
    • 2017-05-18
    • 2019-11-07
    • 2019-10-25
    相关资源
    最近更新 更多