Angular.js html5文件上传到grails控制器

时间:2013-10-14 21:09:48

标签: javascript ajax html5 angularjs grails

我想在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控制器中上传的文件

3 个答案:

答案 0 :(得分:1)

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

这个提示让我走上正轨,在Google的帮助下,我发现这个OPTIONS请求是按照CORS定义的规范进行的预检检查。

来自wikipdia:

  

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

     

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

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

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

之后,该请求被识别为MultipartHttpServletRequest,该文件可以从params

获取

答案 1 :(得分:0)

从小提琴上传时,可以看一眼网络:

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


------WebKitFormBoundarygZi30fqQLB2A9qAC--

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

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

为了确保传递的内容,请在动作接收的params地图上进行调试,并相应地更改动作方法参数名称。

答案 2 :(得分:0)

<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>