NutzCN Logo
问答 UploadAdaptor为什么只支持post和put呢
发布于 3129天前 作者 babizhu 2714 次浏览 复制 上一个帖子 下一个帖子
标签:

因为跨域,因此前段提交的method为options,这样的话UploadAdaptor就报错了
java.lang.IllegalArgumentException: Not POST or PUT, Wrong HTTP method! --> OPTIONS
有没有办法处理呢

16 回复

@wendal(wendal)
谢谢回复,如果我没理解错的话,这个不单纯是跨域的问题,我跟踪代码发现UploadAdaptor只允许method为 POST or PUT
但是ajax提交的话,标准的method为options,这样就出错了

@babizhu 那是跨域时发送的先行请求,里面是没有数据的,确认能跨域之后浏览器才会发真正的post

那也就是说,如果解决了跨域的问题,这个问题就不存在了?我之前都是在方法里面直接加
response.addHeader( "Access-Control-Allow-Origin", "*" );
response.addHeader( "Access-Control-Allow-Headers", "origin, content-type, accept" );
我先试试看,感谢回复

用@Filters加个ActionFilter, 里面判断一下, 如果是OPTIONS就XXX, 否则就通过.

跨域, 更多是通过nginx/apache httpd来做,而非web程序内添加. 原因很简单, 一般来说都不允许跨域调用的, 跨域的API需要额外的安全保障(AccessToken,强制POST操作等).

还是不行,我是这么做的,不知道是不是哪儿有问题

我用一个自定义的filter放在
@Filters({@By(type = CrossOriginFilter.class)})
public class MainModule{
}
对于普通json,这个跨域是没有问题的
然而对于上传图片,客户端还是采用的options作为method,因此服务器依然报错
Not POST or PUT, Wrong HTTP method! --> OPTIONS

增加一个浏览器返回的内容
response的内容
HTTP/1.1 500
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: get, post, put, delete, options
Access-Control-Allow-Headers: origin, content-type, accept
Access-Control-Allow-Credentials: true
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1044
Date: Fri, 22 Apr 2016 16:37:03 GMT
Connection: close
---------------------------
Request Headers
view parsed
OPTIONS /api/hadoop/upload HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Access-Control-Request-Headers: content-type, x-requested-with
Accept: /
Referer: http://localhost:3000/fileExplorer
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4

客户端还是采用的options作为method

把客户端代码贴出来,

options从来都不是用来传表单数据的

客户端并没有用表单而是用的XMLHttpRequest
源代码在这里
hhttps://github.com/react-component/upload/blob/master/src/request.js

@babizhu 贴客户端的代码

感谢回复
在跟踪代码UploadAdaptor代码的过程中,发现即使跳过method的判断,在后期也会在执行到下方的
e = request.getContentType();
if(e == null) {
throw (IllegalArgumentException)Lang.makeThrow(IllegalArgumentException.class, "Content-Type is NULL!!", new Object[0]);
}
这里出问题,因此我在想是不是如你所说,这次请求其实并没有带数据,只是一个测试性的请求,本不应该执行到这里,结果就报错了
思路有些乱,见谅

客户端,代码如下
function getError(option, xhr) {
const msg = cannot post ${option.action} ${xhr.status}';
const err = new Error(msg);
err.status = xhr.status;
err.method = 'post';
err.url = option.action;
return err;
}

function getBody(xhr) {
const text = xhr.responseText || xhr.response;
if (!text) {
return text;
}

try {
return JSON.parse(text);
} catch (e) {
return text;
}
}

export default function upload(option) {
if (typeof XMLHttpRequest === 'undefined') {
return;
}

const xhr = new XMLHttpRequest();
if (xhr.upload) {
xhr.upload.onprogress = function progress(e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
option.onProgress(e);
};
}

const formData = new FormData();

if (option.data) {
Object.keys(option.data).map(key => {
formData.append(key, option.data[key]);
});
}

formData.append(option.filename, option.file);

xhr.onerror = function error(e) {
option.onError(e);
};

xhr.onload = function onload() {
if (xhr.status !== 200) {
return option.onError(getError(option, xhr), getBody(xhr));
}

option.onSuccess(getBody(xhr));

};

xhr.open('post', option.action, true);

// Has to be after .open(). See https://github.com/enyo/dropzone/issues/179
if (option.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}

xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
const headers = option.headers || {};
for (const h in headers) {
if (headers.hasOwnProperty(h)) {
xhr.setRequestHeader(h, headers[h]);
}
}
xhr.send(formData);
}

下面的语句加到改该upload的入口方法处

@Filters({@By(type = CrossOriginFilter.class)})

万分感谢,成功了,我大概总结一下,希望对后面的同学有所帮助,如有错误也希望能提出
对于通过ajax上传图片
需要在函数入口处增加
@Filters({@By(type = CrossOriginFilter.class,args={"*", "get, post, put, delete, options", " X-Requested-With,origin, content-type, accept", "true"})})
另外还是需要手动加入相关跨域的header

response.addHeader( "Access-Control-Allow-Origin", "*" );
response.addHeader( "Access-Control-Allow-Headers", "origin, content-type, accept" );
response.addHeader( "Content-Type", "application/json" );

那CrossOriginFilter就是没起到应有的作用.

可能是吧,我的理解是这样的,不一定对,有问题请指出
不管method是什么,只要跨域,那么浏览器都要求服务器的header里面包括
response.addHeader( "Access-Control-Allow-Origin", "*" );
response.addHeader( "Access-Control-Allow-Headers", "origin, content-type, accept" );
但是如果method不是options,CrossOriginFilter是不会加上这些的,因此浏览器会报错

恩, 我改改

添加回复
请先登陆
回到顶部