繁体   English   中英

Golang AWS API Gateway无效字符'e'寻找值的开始

Golang AWS API Gateway invalid character 'e' looking for beginning of value

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

我正在尝试创建连接到lambda的API网关,该API会解析带有手把的HTML模板,然后将其返回,但是当我在本地甚至使用AWS在测试url上运行它时,都遇到此错误。

{
"errorMessage": "invalid character 'e' looking for beginning of value",
"errorType": "SyntaxError"
}

这是我的SAM模板

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: data-template-renderer
Parameters:
  Stage:
    Type: String
    AllowedValues:
    - dev
    - staging
    - production
    Description: environment values
Resources:
  # Defining the API Resource here means we can define the stage name rather than
  # always being forced to have staging/prod. Also means we can add a custom domain with
  # to the API gateway within this template if needed. Unfortunately there is a side effect
  # where it creates a stage named "Stage". This is a known bug and the issue can be
  # found at https://github.com/awslabs/serverless-application-model/issues/191
  DataTemplateRendererApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Sub "${Stage}-data-template-renderer"
      StageName: !Ref Stage
      DefinitionBody:
        swagger: "2.0"
        basePath: !Sub "/${Stage}"
        info:
          title: !Sub "${Stage}-data-template-renderer"
          version: "1.0"
        consumes:
        - application/json
        produces:
        - application/json
        - text/plain
        - application/pdf
        paths:
          /render:
            post:
              x-amazon-apigateway-integration:
                uri:
                  "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${RenderTemplate.Arn}/invocations"
                httpMethod: POST
                type: aws_proxy
        x-amazon-apigateway-binary-media-types:
        - "*/*"

  RenderTemplate:
    Type: AWS::Serverless::Function
    Properties:
      Environment:
        Variables:
          ENV: !Ref Stage
      Runtime: go1.x
      CodeUri: build
      Handler: render_template
      FunctionName: !Sub 'render_template-${Stage}'
      Timeout: 30
      Tracing: Active
      Events:
        RenderTemplateEndpoint:
          Type: Api
          Properties:
            RestApiId: !Ref DataTemplateRendererApi
            Path: /render
            Method: POST
      Policies:
      - !Ref S3AccessPolicy
      - CloudWatchPutMetricPolicy: {}

  S3AccessPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: data-template-renderer-s3-policy
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: Allow
          Action: s3:GetObject
          Resource: !Sub "arn:aws:s3:::*"
        - Effect: Allow
          Action: s3:PutObject
          Resource: !Sub "arn:aws:s3:::*"

以下是我用于Lambda的代码。 请原谅它可能不是您所见过的最好的Golang代码,但我是Go语言的初学者,因为我主要是PHP开发人员,但是我工作的公司正在创建很多Golang Lambda,所以我开始学习它。

package main

import (
    "bytes"
    "context"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "strings"
    "time"

    "github.com/aymerick/raymond"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/SebastiaanKlippert/go-wkhtmltopdf"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
)

var sess *session.Session

func init() {
    // Setup AWS S3 Session (build once use every function)
    sess = session.Must(session.NewSession(&aws.Config{
        Region: aws.String("us-east-1"),
    }))
}

func main() {
    lambda.Start(handleRequest)
}

type TemplateRendererRequest struct {
    Template string `json:"template"`
    Bucket string `json:"bucket"`
    Type string `json:"type"`
    Data map[string]interface{} `json:"data"`
}

type EmailResponse struct {
    Email string `json:"email"`
}

func handleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    // Unmarshal json request body into a TemplateRendererRequest struct that mimics the json payload
    requestData := TemplateRendererRequest{}
    err := json.Unmarshal([]byte(request.Body), &requestData)
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

    // Get the template object from S3
    result, err := s3.New(sess).GetObject(&s3.GetObjectInput{
        Bucket: aws.String(requestData.Bucket),
        Key:    aws.String(requestData.Template),
    })
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }
    defer result.Body.Close()

    // The S3 Object Body is of type io.ReadCloser
    // below we create a bytes buffer and then convert it to a string so we can use it later
    buf := new(bytes.Buffer)
    buf.ReadFrom(result.Body)
    templateString := buf.String()

    // Parse template through Handlebars library
    parsedTemplate, err := parseTemplate(templateString, requestData)
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

    switch requestData.Type {
    case "pdf":
        return handlePDFRequest(parsedTemplate, requestData)
    default:
        return handleEmailRequest(parsedTemplate)
    }
}

func handleEmailRequest(parsedTemplate string) (events.APIGatewayProxyResponse, error) {
    // Put email parsed template in a struct to return in the form of JSON
    emailResponse := EmailResponse{
        Email: parsedTemplate,
    }
    // JSON encode the emailResponse
    response, err := JSONMarshal(emailResponse)
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

    return events.APIGatewayProxyResponse{
        Body: string(response),
        StatusCode: 200,
        Headers: map[string]string{
            "Content-Type": "application/json",
        },
    }, nil
}

func parseTemplate(templateString string, request TemplateRendererRequest) (string, error) {
    result, err := raymond.Render(templateString, request.Data)

    return result, err
}

func handlePDFRequest(parsedTemplate string, requestData TemplateRendererRequest) (events.APIGatewayProxyResponse, error) {
    pdfBytes, err := GeneratePDF(parsedTemplate)
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

    keyNameParts := strings.Split(requestData.Template, "/")
    keyName := keyNameParts[len(keyNameParts)-1]
    pdfName := fmt.Sprintf("%s_%s.pdf", keyName, time.Now().UTC().Format("20060102150405"))
    _, err = s3.New(sess).PutObject(&s3.PutObjectInput{
        Bucket: aws.String(requestData.Bucket),
        Key:    aws.String(pdfName),
        Body:   bytes.NewReader(pdfBytes),
    })

    b64Pdf := base64.StdEncoding.EncodeToString(pdfBytes)
    return events.APIGatewayProxyResponse{
        Body: b64Pdf,
        StatusCode: 200,
        Headers: map[string]string{
            "Content-Type": "application/pdf",
        },
        IsBase64Encoded: true,
    }, nil
}

func GeneratePDF(templateString string) ([]byte, error) {
    pdfg, err := wkhtmltopdf.NewPDFGenerator()
    if err != nil {
        return nil, err
    }

    // Pass S3 Object body (as reader io.Reader) directly into wkhtmltopdf
    pdfg.AddPage(wkhtmltopdf.NewPageReader(strings.NewReader(templateString)))

    // Create PDF document in internal buffer
    if err := pdfg.Create(); err != nil {
        return nil, err
    }

    // Return PDF as bytes array
    return pdfg.Bytes(), nil
}

// https://stackoverflow.com/questions/28595664/how-to-stop-json-marshal-from-escaping-and
func JSONMarshal(t interface{}) ([]byte, error) {
    buffer := &bytes.Buffer{}
    encoder := json.NewEncoder(buffer)
    encoder.SetEscapeHTML(false)
    err := encoder.Encode(t)
    return buffer.Bytes(), err
}

我试图在高处和低处寻找解决方案,但找不到为什么我会收到这个非常奇怪的错误,但不是很有帮助。 感谢您抽出宝贵的时间和帮助

1 个回复

感谢@Anzel向我指出了正确的方向,因此我决定查看该request.Body正文似乎通过将*/*添加到API Gateway Binary媒体类型中,现在即使请求是经过编码的,也可以看到正如消息中所说,第一个字母确实是一个e

所以我改变了这个:

// Unmarshal json request body into a TemplateRendererRequest struct that mimics the json payload
    requestData := TemplateRendererRequest{}
    err := json.Unmarshal([]byte(request.Body), &requestData)
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

对此:

// Unmarshal json request body into a TemplateRendererRequest struct that mimics the json payload
    requestData := TemplateRendererRequest{}

    b64String, _ := base64.StdEncoding.DecodeString(request.Body)
    rawIn := json.RawMessage(b64String)
    bodyBytes, err := rawIn.MarshalJSON()
    if err != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", err.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, err
    }

    jsonMarshalErr := json.Unmarshal(bodyBytes, &requestData)
    if jsonMarshalErr != nil {
        return events.APIGatewayProxyResponse{
            Body: fmt.Errorf("Error: %s ", jsonMarshalErr.Error()).Error(),
            StatusCode: 400,
            Headers: map[string]string{
                "Content-Type": "text/plain",
            },
        }, jsonMarshalErr
    }

根据我在网上看到的内容,您还可以更改此设置:

rawIn := json.RawMessage(b64String)
bodyBytes, err := rawIn.MarshalJSON()

对此:

[]byte(b64String)

现在,当我执行CURL请求并将其输出到文件时,我可以正确获取PDF。

1 Golang无效字符'b'寻找值的开始

我正在尝试在其中发布带有 xml 消息的 json。 但是它返回: 我认为可能的原因是我试图编组不是 json 格式的返回主体。 错误发生在这一行: ...

2016-08-14 14:14:20 6 54459   json/ xml/ go
5 用'e' Jquery连接字符串

我在用 " 和 ' 连接字符串时遇到问题。 我想向 Jquery 发送一个命令,单击具有我作为参数传递的标题的 div。 需要获取它才能在 jquery 函数中执行: 我有这个功能: 执行函数时出现错误,因为变量的值是 'div [title =' Sintra Spot ']' 我需 ...

6 为什么type =“数字”接受'e'字符? [重复]

这个问题已经在这里有了答案: 为什么HTML输入类型为“数字”,但允许在字段中输入字母“ e”? 6个答案 有人可以解释为什么输入type=number接受e字符吗? 这确实让我感到困惑,我对此很疑惑。 ...

7 replace()函数不替换'e'字符

我的代码应该识别元音字母并使用replace()函数从输入字符串中删除它们。 但是除了'e'字母外,它的工作正常。 如果输入是"Hey look Words!" 输出是"Hey lk Wrds!" 。 仅当“元音”字符串仅等于"e"或"eE"时才识别'e'! 我很想知道为什么 ...

2015-10-02 15:09:00 3 138   python
9 Python scrapy shell终端KeyError:'e'

在我的 Windows 命令提示符中,“python3 -m scrapy shell”https://scrapy.org””按预期工作,并提供了一个交互式 shell,按预期工作。 但是,如果我打开 Windows 终端并使用适用于 Linux 的 Windows 子系统键入“ubuntu”, ...

10 Python 'e' 符号

我正在尝试使用1e6返回 1000000,但我需要将 '6' 设置为变量。 但 给我一个语法错误。 python 参考文档没有关于如何使用变量而不是整数来实现这一点的详细信息。 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2021 STACKOOM.COM