【问题标题】:Angular.js html5 file upload to grails controllerAngular.js html5 文件上传到 grails 控制器
【发布时间】:2013-10-14 21:09:47
【问题描述】:

我希望在 JSFiddle 的这个 angularjs html5 上传示例中删除文件:

http://jsfiddle.net/danielzen/utp7j/

由 grails 控制器上传到后端。 在尝试完成此操作时,我创建了一个简单的 grails 控制器:

class UploadController {

    def index() {

        if (request instanceof MultipartHttpServletRequest){
            for(filename in request.getFileNames()){
                MultipartFile file = request.getFile(filename)
                String newFileName = UUID.randomUUID().toString() + file.originalFilename.substring(file.originalFilename.lastIndexOf("."))
                file.transferTo(new File("/home/myuser/temp/$newFileName"))
            }
        }

        render "ok"
    }

}

然后我打开一个 ajax XmlHttpRequest2 POST 到 grails 控制器:

xhr.open("POST", "http://localhost:8080/app/upload")

但 grails 控制器无法将请求转换为 MultipartHttpServletRequest, 可能是因为这种调用 grails 控制器的 ajax 方式没有使用 multipart/form-data 上传方式。 我尝试在 xhr 上设置 enctype multipart/form-data 的标头无济于事。

我现在完全陷入困境,想知道如何在 grails 控制器中处理上传的文件

【问题讨论】:

  • 看看params里面有什么?

标签: javascript ajax html angularjs grails


【解决方案1】:

我使用内置的 Chrome 开发工具跟踪了由 XmlHttpRequest.send(formData) 调用生成的 POST 请求。 令我惊讶的是,请求方法不是 enctype=multipart/form-data 的 POST 类型,而是 OPTIONS 类型。

这个提示让我走上了正轨,在 Google 的帮助下,我发现这个 OPTIONS 请求是作为 CORS 定义的每个规范的预检检查发生的。

来自维基百科:

跨域资源共享 (CORS) 是一种允许 网页上的 JavaScript 向另一个域发出 XMLHttpRequests, 不是 JavaScript 源自的域。[1]这样的“跨域” 否则,请求将被 Web 浏览器禁止,同样 源安全策略。 CORS 定义了浏览器和 服务器可以交互以确定是否允许 跨域请求。[2]它比只允许更强大 同源请求,但比简单地允许所有请求更安全 这样的跨域请求。

CORS 标准通过添加允许服务器的新 HTTP 标头来工作 为允许的源域提供资源。浏览器支持这些 标头并执行它们建立的限制。此外,对于 可能对用户数据造成副作用的 HTTP 请求方法(在 特别是对于 GET 以外的 HTTP 方法,或者对于 POST 使用 某些 MIME 类型),规范要求浏览器 “预检”请求,从服务器请求支持的方法 带有 HTTP OPTIONS 请求标头,然后,在“批准”时 服务器,使用实际的 HTTP 请求发送实际的请求 方法。服务器还可以通知客户端是否“凭据” (包括 Cookie 和 HTTP 身份验证数据)应与 请求。

因为我的 grails (tomcat) 服务器是从 localhost:8080 运行的,而我的 html/javascript 是从 WebStorm IDE 的 localhost:63342 上的内置 http 服务器上运行的,所以 XmlHttpRequest 实际上是 CORS,因为不同的端口号在同一个主机上也被认为是跨域的。

因此,我需要确保 Grails (tomcat) 服务器允许这样做,并且我能够使用出色的 Grails cors 插件来做到这一点,该插件可以在 https://github.com/davidtinker/grails-cors 找到

之后请求被识别为MultipartHttpServletRequest,并且可以从params获取文件

【讨论】:

    【解决方案2】:

    从你得到的小提琴上传时看看网络:

    ------WebKitFormBoundarygZi30fqQLB2A9qAC
    Content-Disposition: form-data; name="uploadedFile"; filename="file.txt"
    Content-Type: text/javascript
    
    
    ------WebKitFormBoundarygZi30fqQLB2A9qAC--
    

    我相信你会得到一个“uploadedFile”作为 Grails 的参数键,所以你可以编写一个控制器动作,例如:

    def uploadFile(CommonsMultipartFile uploadedFile) {
        ///accessing the file data: uploadedFile.bytes, uploadedFile.contentType, uploadedFile.originalFilename
    }
    

    为了确定传递的是什么,请对操作接收的参数映射进行调试,并相应地更改操作方法参数名称。

    【讨论】:

    • 这是预期的结果,但由于 XmlHttpRequest 的 CORS(跨源资源共享),我遇到了问题。有关详细信息,请参阅我的答案。
    【解决方案3】:
    <body ng-controller="FileUploadCtrl">
     $scope.selectedFile=[]; 
                          $scope.onFileSelect = function ($files) { 
                                $scope.uploadProgress = 0; 
                                $scope.selectedFile = $files; 
                            }; 
                            $scope.myData = {}; 
    
                          $scope.upload = function(){ 
                                var formData = new FormData(); 
                                formData.append("file", $scope.selectedFile[0]); 
                                formData.append("data", myData.message.value); 
                                $http.post('api/upload', formData, { 
                                    transformRequest: angular.identity, 
                                    headers: { 
                                        'enctype': 'multipart/form-data', 
                                        'Content-Type': undefined 
                                    } 
                                }) 
                                .success(function(){ 
                                    alert("done"); 
                                }) 
                                .error(function(){ 
                                    alert("failed"); 
                        }); 
    
    
    </body>
    
    <form ng-submit="upload()" method="post" enctype="multipart/form-data" name="myData">       <div>
    
        <textarea  rows="3" name="message" placeholder="Send Message"></textarea>               
              <input type="file" ng-file-select="onFileSelect($files)" /> 
            </div> 
            <button type="submit" class="btn btn-primary">upload</button> 
            </form>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多