在我的一个angularJS项目中,我决定使用ng-droplet,这允许我创建拖放区域以通过我的api在服务器上上传图像。
设置插件后,我试了一下,但是我得到了:
XMLHttpRequest cannot load http://myapi.com/api/items. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8383' is therefore not allowed access. The response had HTTP status code 500.
Access-Control-Allow-Origin设置为" *"在服务器端,我在其他api端点上做请求没有问题。
所以我试着看看插件是如何创建请求并发送的,这里是如何:
$scope.uploadFiles = function uploadFiles() {
// Reset...
$scope.isError = false;
var httpRequest = new $window.XMLHttpRequest(),
formData = new $window.FormData(),
queuedFiles = $scope.filterFiles($scope.FILE_TYPES.VALID),
fileProperty = $scope.options.useArray ? 'file[]' : 'file',
requestLength = $scope.getRequestLength(queuedFiles),
deferred = $q.defer();
// Initiate the HTTP request.
httpRequest.open('post', $scope.options.requestUrl, true);
/**
* @method appendCustomData
* @return {void}
*/
(function appendCustomData() {
if (!$scope.options.disableXFileSize) {
// Setup the file size of the request.
httpRequest.setRequestHeader('X-File-Size', requestLength);
}
// ...And any other additional HTTP request headers, and POST data.
$scope.addRequestHeaders(httpRequest);
$scope.addPostData(formData);
})();
/**
* @method attachEventListeners
* @return {void}
*/
(function attachEventListeners() {
// Define the files property so that each listener has the same interface.
$scope.listeners.files = queuedFiles;
$scope.listeners.deferred = deferred;
$scope.listeners.httpRequest = httpRequest;
// Configure the event listeners for the impending request.
$scope.listeners.progress();
$scope.listeners.success();
$scope.listeners.error();
})();
// Iterate all of the valid files to append them to the previously created
// `formData` object.
$angular.forEach(queuedFiles, function forEach(model) {
formData.append(fileProperty, model.file);
});
// Voila...
$scope.isUploading = true;
httpRequest.send(formData);
return deferred.promise;
};
正如你所看到的,他没有使用$ http而是$ window.XMLHttpRequest。
所以我尝试在同一个端点(http://myapi.com/api/items)的测试控制器上进行文件上传,但这次使用$ http。
像这样:
var fileInput = document.getElementById('uploadedFile');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('title', "rfsdfsd");
formData.append('description', "rfsdfhgfhfgsd");
formData.append('category', 1);
formData.append('price', 20);
formData.append('file', file);
$http.post('http://myapi.com/api/items', formData, {
headers: {
'Content-Type': undefined
}
});
请注意' Content-Type&#39 ;: undefined ,因为当我尝试这个时,它有效!文件实际上传,我得到200响应代码。
如果我将Content-Type从未定义更改为" multipart / form-data"或其他任何内容,或者如果我删除该行,我从上面得到错误并上传失败。
在角度文档中,据说将Content-Type设置为" undefined"明确删除标题:
要基于每个请求显式删除通过$ httpProvider.defaults.headers自动添加的标头,请使用headers属性,将所需标头设置为undefined。
似乎删除Content-Type标头的事实是它与$ http一起使用的部分原因。
所以我也尝试在这个测试控制器中使用$ window.XMLHttpRequest:
var httpRequest = new $window.XMLHttpRequest();
var fileInput = document.getElementById('uploadedFile');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('title', "rfsdfsd");
formData.append('description', "rfsdfhgfhfgsd");
formData.append('category', 1);
formData.append('price', 20);
formData.append('file', file);
httpRequest.open('post', 'http://myapi.com/api/items', true);
httpRequest.send(formData);
但是这个给了我和以前一样的CORS错误。我还尝试手动添加Content-Type标头,如下所示:
httpRequest.setRequestHeader('Content-Type', undefined);
或
httpRequest.setRequestHeader('Content-Type', null);
或""," "等等,但似乎没有任何作用,我总是得到:
POST http://myapi.com/api/items 400 (Bad Content-Type header value: 'undefined')
那么,为什么它可以使用$ http和Content-Type设置为undefined,如何修改ng-droplet使其工作? (我不想用$ http而不是$ window.XMTHttpRequest重写整个事情。)
为什么在使用$ window.XMTHttpRequest或没有Content-Type标头的$ http或者Content-Type设置为未定义的任何内容时会出现此错误?
Ps :如果有人问:ng-droplet提供了自己的方式来添加POST数据,这是我使用的端点所需要的。像这样:
$scope.interface.setPostData({title: "test", description: 'testetstsetest', price: 20, category: 1});
所以它不是问题来源。
编辑:
我解决了它,我忘了我有一个Http拦截器,它自动为所有$ http请求添加一个Authorization标头。我不知道的事情是它没有添加到$ window.XMLHTTPRequest。所以我手动添加它,现在它可以工作。