Grails 4、Ubuntu 20、嵌入式 Tomcat - 请求中没有多部分文件

Posted

技术标签:

【中文标题】Grails 4、Ubuntu 20、嵌入式 Tomcat - 请求中没有多部分文件【英文标题】:Grails 4, Ubuntu 20, Embedded Tomcat - No Multipart files in request 【发布时间】:2021-03-19 02:22:05 【问题描述】:

大约一周以来,我一直在尝试解决 grails 4 应用程序的 prod 环境部署问题。当我通过 run-app 或 java -jar warfile.war 在本地运行我的应用程序时,我可以上传文件并在我的控制器中使用多部分内容。当我在 lightail ubuntu 20 服务器上部署运行应用程序时,由于某种原因,这些部件根本不存在。

UI 表单代码:

<form id="file-form-$attrs.id" enctype="multipart/form-data">
        <input style="display:none;" id="$attrs.id-file" type="file" name="file"
               accept="image/png, image/jpeg, image/tiff"/>
    </form>

UI ajax/js 代码:

var jForm = new FormData($('#file-form-'+id)[0]);
        jForm.append("uploadField", $("#file-form-"+id).find('input[type="file"]').get(0).files[0]);

        $.ajax(
            url: '/files/uploadImage',
            type: "POST",
            data: jForm,
            enctype: 'multipart/form-data',
            processData: false,
            cache: false,
            contentType: false
        ).done(function(data) 
            // ...
        ).fail(function(jqXHR, textStatus) 
            // ...
        );

控制器(请注意,这里所有的日志语句都是为了清楚起见,它写得很丑,一旦清楚就会被清理掉):

    def uploadImage() 
        try 
            log.debug("FilesController.uploadImage: IN for user $session.user?.id")
            if (request instanceof MultipartHttpServletRequest) 
                MultipartHttpServletRequest rqst = (MultipartHttpServletRequest) request
                def myFile = params['uploadField']
                params.each  k, v ->
                    log.debug("params k $k, v $v")
                
                request.requestHeaders.each k, v ->
                    log.debug("headers k $k, v $v")
                
                def f
                log.debug("parts " + request.parts?.size())
                request.parts.each part ->
                    log.debug("part $part.name")
                    if (f == null) f = part
                
                log.debug("fileNames: $request.getFileNames()")
                request.getFileNames().each  String fileName ->
                    log.debug("fileName: $fileName")
                
                request.fileMap.each  String name, MultipartFile file ->
                    log.debug("Looping fileMap: name: $name and file $file")
                    if (f == null) f = file
                
                log.debug('file: ' + f)
                if (f == null) f = myFile
                log.debug('file: ' + f)

                log.debug("FilesController.uploadImage: calling imageService for user $session.user?.id ")
                log.debug("imageService " + imageService)
                File file = imageService.saveImage(f, session.user)
                render text: file?.id
                return
            
         catch (Exception e) 
            log.error("FilesController.uploadImage: error $e.getMessage()")
        
        render text: ''
    

日志(在产品中):2020-12-07 18:11:51.977 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : FilesController.uploadImage: IN for user uuid-xxxxx 2020-12-07 18:11:51.978 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : params k controller, v files 2020-12-07 18:11:51.978 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : params k format, v null 2020-12-07 18:11:51.978 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : params k action, v uploadImage 2020-12-07 18:11:51.980 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k host, v [xxx.com] 2020-12-07 18:11:51.980 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k connection, v [keep-alive] 2020-12-07 18:11:51.980 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k content-length, v [3477461] 2020-12-07 18:11:51.980 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k accept, v [*/*] 2020-12-07 18:11:51.981 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k x-requested-with, v [XMLHttpRequest] 2020-12-07 18:11:51.981 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k user-agent, v [Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/87.0.4280.67 Safari/537.36] 2020-12-07 18:11:51.981 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k content-type, v [multipart/form-data; boundary=----WebKitFormBoundaryNqkRdP2KDJ3aJYMb] 2020-12-07 18:11:51.981 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k origin, v [https://example.com] 2020-12-07 18:11:51.981 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k sec-fetch-site, v [same-origin] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k sec-fetch-mode, v [cors] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k sec-fetch-dest, v [empty] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k referer, v [https://example.com/toolsList/list?toolSetID=2c9a8202763005520176300c0254001d] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k accept-encoding, v [gzip, deflate, br] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k accept-language, v [en-US,en;q=0.9] 2020-12-07 18:11:51.982 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : headers k cookie, v [pvisitor=ff1209b4-edb0-4246-b877-8e42fe356908; JSESSIONID=C8C338FA7AC3DA7F0A967492864939BF] 2020-12-07 18:11:51.983 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : parts 0 2020-12-07 18:11:51.983 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : fileNames: java.util.LinkedHashMap$LinkedKeyIterator@5f7cb675 2020-12-07 18:11:51.983 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : file: null 2020-12-07 18:11:51.983 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : file: null 2020-12-07 18:11:51.984 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : FilesController.uploadImage: calling imageService for user uuid-xxx 2020-12-07 18:11:51.984 DEBUG --- [nio-8443-exec-2] xxx.files.FilesController : imageService xxx.files.ImageService@5c93194d 2020-12-07 18:11:51.985 INFO --- [nio-8443-exec-2] xxx.files.ImageService : FilesService.saveImage: IN for uuid-xxx named null 2020-

在本地,那里有一个文件。

在我的 application.yml 中:

grails:
    disableCommonsMultipart: false
    web:
        disable:
            multipart: false

我不知道为什么在我的本地环境中接收到文件内容,但在生产环境中却没有。我无法想象 aws lightsail 会从 https 请求中剥离内容。在本地,我使用的是 http 而不是 https,不知道为什么这很重要。

有什么想法吗?提前感谢您提供的任何见解。

【问题讨论】:

您的生产配置可能不同。您能否尝试使用环境生产在本地运行? 嘿@PuneetBehl,我可以在 prod 模式下本地运行(通过 java -jar 对 war 文件),它工作正常。我一直在尝试将 multipartResolver 配置为: multipartResolver(org.springframework.web.multipart.commons.CommonsMultipartResolver) bean -> System.out.println("multipartResolver IN") maxInMemorySize=26214400 maxUploadSize=26214400 maxUploadSizePerFile=26214400 这导致以下异常: FileUploadBase$IOFileUploadException:处理多部分/表单数据请求失败。直播意外结束。 FWIW,我现在已经实现了一个扩展 CommonsMultipartResolver 的 CustomMultipartResolver。我重写了 resolveMultipart(HttpServletRequest) 方法并检查了这些部分。在我的本地环境中运行,我在部件集合中有一个条目。在生产中运行它,集合中有 0 个部件。关于无法填充零件集合的上游可能有什么想法?这可能是与网络服务器无法将文件字节写入 /tmp 文件位置相关的权限(我已确保用户具有权限)? 我现在已经从 lightsail 实例外部的机器以及通过 ssh 在虚拟实例上运行 curl 调用。在外部时,请求对象上没有可用的正文部分。如果我在虚拟机上对文件进行 curl 发布,则会在请求中找到正文部分。所以,我怀疑在 lightsail 防火墙内发生了一些事情,可能是 mimetype 限制。不过,我没有发现任何文件表明发生了这样的事情。如果那里有任何光帆大师,请告诉我。反馈/输入赞赏。谢谢 更新到 Grails 4.0.5 后应该会解决此问题 【参考方案1】:

最终,问题被证明与 ssl 相关。我使用的 grails 版本是 4.0.3。对于那个版本,嵌入的 tomcat 依赖是 org.springframework.boo:spring-boot-starter-tomcat 并且被拉取的版本是 2.1.13.RELEASE。该 Spring Boot 库利用了 9.0.31 版的 tomcat。找到这篇文章 Multipart file upload using spring boot with tomcat version 9.0.31 is failing 后,只需指定一个 tomcat 版本即可解决在 ssl 上解析多部分文件的问题:

compile "org.apache.tomcat.embed:tomcat-embed-websocket:9.0.33"
compile "org.apache.tomcat.embed:tomcat-embed-core:9.0.33"
compile "org.apache.tomcat.embed:tomcat-embed-el:9.0.33"
compile "org.apache.tomcat:tomcat-juli:9.0.33"
compile "org.apache.tomcat:tomcat-annotations-api:9.0.33"

我希望它可以节省其他人一些时间。和平。

【讨论】:

以上是关于Grails 4、Ubuntu 20、嵌入式 Tomcat - 请求中没有多部分文件的主要内容,如果未能解决你的问题,请参考以下文章

Grails 4:邮件插件在 Elastic Beanstalk 上运行时无法读取“密码”属性

Grails clean 命令在 Ubuntu docker 容器中给出错误

Elasticsearch集群搭建1Welcome to my ELK world!

Grails 和 .gitigore

如何从 Grails 中正确删除 H2

Grails 3 - 配置嵌入式 Tomcat 绑定地址