【发布时间】:2019-11-13 17:13:33
【问题描述】:
我正在尝试将文件从 React 前端上传到 Scala/Play Framework 后端,但它无法正常工作。
所以我有一个上传文件并调用handleUpload的按钮:
handleUpload=()=>{
if(this.state.file!=null){
console.log('value of this.state.file: ', this.state.file)
var dataSend = new FormData();
dataSend.append('file_upload', this.state.file);
console.log('value of dataSend before send: ', dataSend);
this.setState({lastCommand: 'file_upload'}, ()=>{
this.props.sendRequest({
url: "http://localhost:9000/upload",
method: "post",
multipart: true,
data:{
payload:{
data: dataSend
}
}
});
})
}
}
this.props.sendRequest 在我的操作 (Redux) 中,如下所示:
export const request = payload => {
return function(dispatch) {
console.log("value of payload in actions request: ", payload)
var config = {}
if (payload.method=="post"||payload.method=="patch"){
config = {
url: payload.url,
method: payload.method,
withCredentials: true,
data: payload.data,
}
if('multipart' in payload && payload.multipart){
config.headers = { 'Content-Type': 'multipart/form-data' }
}
}else if (payload.method=='get'){
config = {
url: payload.url,
method: payload.method,
withCredentials: true,
}
}
console.log('value of config before send in actions/request: ', config);
axios(config)
.then(response=>{
return dispatch({
val: response,
type: (payload.method=="post"||payload.method=="patch")?"POST_RETURN_SUCCESSFUL":"GET_RETURN_SUCCESSFUL",
sentID: ('sentID' in payload)?payload.sentID:null
})
})
.catch(error=>{
console.log('there was an error in request return in actions', error);
return dispatch({
val: error,
type: (payload.method=="post"||payload.method=="patch")?"POST_RETURN_ERROR":"GET_RETURN_ERROR",
sentID: ('sentID' in payload)?payload.sentID:null
})
});
};
}
这是上面记录的控制台配置的值:
value of config before send in actions/request:
{…}
data: {…}
payload: {…}
data: FormData { }
<prototype>: Object { … }
<prototype>: Object { … }
headers: {…}
"Content-Type": "multipart/form-data"
<prototype>: Object { … }
method: "post"
url: "http://localhost:9000/upload"
withCredentials: true
请注意,虽然表单数据看起来是空的,但这是 Web 控制台无法显示它的产物 (How to inspect FormData?)
这应该在我的游戏框架中达到以下路线(在我的config/routes 文件中定义):
+nocsrf
POST /upload controllers.PostController.admin_upload
其中+nocsrf 只是一个防止跨站点请求伪造的处理程序。
注意:我发送到前端的 url "http://localhost:9000/upload"。
我的上传函数controllers.PostController.admin_upload是一个简单的hello_there
def admin_upload[T]:Action[AnyContent] = Action.async {request: Request
[AnyContent] => Future {
println("****************************")
println("inside admin_upload")
println("****************************")
var responseVal = new Response().standard_response("/admin/patch", "DUMMY - STILL WORKING ON ROUTE")
Ok(responseVal)
}(ec)
}
我在后端没有控制台日志记录,我在前端收到 400 NOT FOUND 错误。
这是我的网络请求标头:
Host: localhost:9000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data
Content-Length: 23
Origin: http://localhost:3000
Connection: keep-alive
Referer: http://localhost:3000/admin
Cookie: PLAY_SESSION=SUPERDOOPERSECRETDAWG
和响应头:
HTTP/1.1 400 Bad Request
Vary: Origin
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
X-Permitted-Cross-Domain-Policies: master-only
Date: Wed, 13 Nov 2019 17:08:34 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 1170
我完全迷路了,这应该可以。
什么坏了?
编辑:
如果我在 axios 请求上删除 Content-Type 标头并控制台输出结果,我 确实 进入 admin_upload 函数但请求正文当然是空的,因为我还没有发送表单。所以我把问题缩小到“如何发送正确的内容类型标志来播放框架?”
****************************
inside admin_upload
****************************
value of request.body:
AnyContentAsJson({"payload":{"data":{}}})
request.body.asMultipartFormData
None
编辑编辑:
即使是最简单的示例,如下所示:https://www.playframework.com/documentation/2.7.x/ScalaFileUpload
似乎不起作用。
def admin_upload = Action(parse.multipartFormData) { request =>
println("****************************")
println("inside admin_upload")
println("****************************")
println(request.body)
var responseVal = new Response().standard_response("/admin/patch", "DUMMY - STILL WORKING ON ROUTE")
Ok(responseVal)
}
编辑编辑编辑:
好的 - 这确实在 Insomnia 中工作,我的配置不正确。这意味着问题是 axios 无法正常工作,我会向他们发送错误报告。
【问题讨论】:
-
您是否尝试过手动测试上传?使用卷曲?跟踪中的请求 URI/路径在哪里?
-
所以,我现在正在手动测试 - 我正在使用失眠症(如邮递员)。放弃 Content-Type 标头是可行的,但我还不知道这是否允许我发送表单数据。有什么奇怪的。 (如果我使用 Content-Type,我会得到
For request 'POST /upload' [Missing boundary header])。 -
当您打印请求标头时,您能否显示您正在访问的路线。你走对路了吗?
-
对不起 - 见上面的编辑。我认为播放框架没有正确看到
Content-Type标头。 -
播放正在正确使用内容类型
标签: reactjs scala session file-upload playframework