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

Groovy解析含multipart/form-data的APIGatewayProxyRequestEvent遇问题

问题背景

我正尝试将一款清理CSV/Excel文件的命令行应用转换为AWS Lambda函数,已完成上传但遇到依赖问题。为测试关键功能,针对函数代码编写了Spock单元测试,但测试失败。

相关测试与代码

测试代码

package com.mikebuyshouses.dncscrubber.awsServices

import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent
import com.mikebuyshouses.dncscrubber.awsServices.providers.TestPathProvider
import com.mikebuyshouses.dncscrubber.utils.FileUtils
import spock.lang.Specification

class ApiRequestHandlerTest extends Specification {
    def "parseRequestEvent should actually write the input file from the request event"() {
        setup:
        def stubRequestEvent = Stub(APIGatewayProxyRequestEvent)
        stubRequestEvent.getHeaders() >> ["Content-Type": "multipart/form-data;boundary=YRPyKRi1Bb3sIDcW"]
        stubRequestEvent.getIsBase64Encoded() >> true;
        stubRequestEvent.getBody() >> """
------WebKitFormBoundaryYRPyKRi1Bb3sIDcW\r
Content-Disposition: form-data; name="inputFile"; filename="test.csv"\r
Content-Type: text/csv\r
\r
Number,Sale Date,Address,City,State,Zip,Parcel,Township,Removed,Removed Date,Bankruptcy #,Redemption Days,Cause #,Receive Date,Receive Time,Total Judgement,Plaintiff,Et al,Attorney,Phone,User Fee,Sheriff Fee,Ad Cost,Delinquent Tax,Total Fees,Defendant,Judgement,Interest 1,Interest 2,Additional Charges,Lien Holder 1,Lien Holder 1 Judgement,Lien Holder 1 Interest 1,Lien Holder 1 Interest 2,Lien Holder 1 Additional Charges,Lien Holder 2,Lien Holder 2 Judgement,Lien Holder 2 Interest 1,Lien Holder 2 Interest 2,Lien Holder 2 Additional Charges,Lien Holder 3,Lien Holder 3 Judgement,Lien Holder 3 Interest 1,Lien Holder 3 Interest 2,Lien Holder 3 Additional Charges,Lien Holder 4,Lien Holder 4 Judgement,Lien Holder 4 Interest 1,Lien Holder 4 Interest 2,Lien Holder 4 Additional Charges,Lien Holder 5,Lien Holder 5 Judgement,Lien Holder 5 Interest 1,Lien Holder 5 Interest 2,Lien Holder 5 Additional Charges,Lien Holder 6,Lien Holder 6 Judgement,Lien Holder 6 Interest 1,Lien Holder 6 Interest 2,Lien Holder 6 Additional Charges,Lien Holder 7,Lien Holder 7 Judgement,Lien Holder 7 Interest 1,Lien Holder 7 Interest 2,Lien Holder 7 Additional Charges,Lien Holder 8,Lien Holder 8 Judgement,Lien Holder 8 Interest 1,Lien Holder 8 Interest 2,Lien Holder 8 Additional Charges,Lien Holder 9,Lien Holder 9 Judgement,Lien Holder 9 Interest 1,Lien Holder 9 Interest 2,Lien Holder 9 Additional Charges,,Grand Total\r
1,09/15/2023,1001 Main Street,Indianapolis,IN,46220,,BRO,N,,,,123456789MF123456,07/14/2023,,44202.67,FAKE BANK,,CARLISLE,(216) 555-1234,300,66,345.42,0,711.42,DOUGLAS H LOPEZ,44202.67,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,0,0,0,0,,44914.09\r
\r
------WebKitFormBoundaryYRPyKRi1Bb3sIDcW--\r
""".bytes.encodeBase64()

        ApiRequestHandler apiRequestHandler = new ApiRequestHandler().with { ApiRequestHandler handler ->
            handler.pathProvider = new TestPathProvider();

            return handler;
        }

        when:
        apiRequestHandler.parseRequestEvent(stubRequestEvent)

        then:
        new File("${FileUtils.TestDirectoryPath}/${FileUtils.InputPathPart}/test.csv").exists()

        cleanup:
        new File("${FileUtils.TestDirectoryPath}/${FileUtils.InputPathPart}/test.csv").delete()
    }

}

被测代码

该测试针对以下方法:

RequestBodyModel parseRequestEvent(APIGatewayProxyRequestEvent request) {
    byte[] bodyBytes = request.getBody().getBytes("UTF-8");
    if (request.getIsBase64Encoded())
        bodyBytes = Base64.getDecoder().decode(bodyBytes);

    RequestBodyModel model = new RequestBodyModel();

    FileUpload.parse(bodyBytes, request.getHeaders().get('Content-Type'))
        .each { FileItem fileItem ->
            if (fileItem.getFieldName().equals("inputFile")) {
                File inputFile = FileUtils.CreateFileIfNotExists("${this.pathProvider.getBaseInputPath()}/${fileItem.getName()}");
                fileItem.write(inputFile);
                model.inputFile = inputFile;
                return;
            }

            if (fileItem.getFieldName().equals("outputFileExtension")) {
                model.outputFileExtension = fileItem.getString();
                return;
            }

            if (fileItem.getFieldName().equals("shouldExportDncRecords")) {
                model.shouldExportDncRecords = Boolean.valueOf(fileItem.getString());
                return;
            }
        }

    return model;
}

用到的模型类RequestBodyModel定义如下:

class RequestBodyModel {
    File inputFile;
    boolean shouldExportDncRecords;
    String outputFileExtension;
}
测试结果

测试失败,目标文件未生成;调试发现FileUpload.parse()未返回任何FileItem。

使用的依赖库
  • delight-fileupload(基于Apache Commons FileUpload)
  • AWS Lambda Java Events
  • Spock(单元测试框架)
核心问题

如何使用FileUpload或类似工具解析上述测试中的multipart/form-data请求,并正常获取FileItem进行处理?


内容的提问来源于stack exchange,提问作者Mike Warren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:02:12