我创建了一个简单的表单,以便将单个PDF文件上传到数据库的Blob中。我正在使用thymeleaf + spring boot和dropzone.js。
我收到405错误-上传文件时不允许使用该方法。
我已经尝试在控制器方法中添加@ResponseBody,但是错误仍然相同。
这是我的pdf-upload.html(百里香模板):
<html>
<head>
...
<script type="text/javascript">
Dropzone.options.myAwesomeDropzone = {
// url: "[[@{/vouchers/uploadPdfFile}]]",
paramName : "file", // The name that will be used to transfer the file
maxFilesize : 10, // MB
addRemoveLinks : true,
acceptedFiles : ".pdf",
maxFiles : 1,
// headers: {
// 'X-CSRF-TOKEN': $('meta[name="token"]').attr('content')
// }
};
</script>
....
</head>
....
<form th:action="@{/vouchers/uploadPdfFile}"
enctype="multipart/form-data"
method="post" class="dropzone needsclick dz-clickable"
id="my-awesome-dropzone">
<div class="col-12" id="dropzone">
<div class="dz-message needsclick">
Drop the PDF that will be attached to the Voucher...<br>
</div>
</div>
<input type="hidden" id="hd_voucher_id" th:value="${voucher.id}">
</form>
....
</html>
我的控制器如下:
@RequestMapping(value = "/uploadPdfFile", method = RequestMethod.POST)
public String uploadPdfPost(MultipartHttpServletRequest request) {
try {
Iterator<String> itr = request.getFileNames();
while (itr.hasNext()) {
String uploadedFile = itr.next();
MultipartFile file = request.getFile(uploadedFile);
String mimeType = file.getContentType();
String filename = file.getOriginalFilename();
byte[] bytes = file.getBytes();
FileUpload newFile = new FileUpload(filename, bytes, mimeType);
//fileUploadService.uploadFile(newFile);
}
} catch (Exception e) {
return "vouchers/pdf-upload";
}
return "vouchers/pdf-upload";
}
提交表单时,出现我前面提到的405错误。
在日志控制台中,出现以下错误:
2019-07-16 15:45:27 WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
2019-07-16 15:45:27 DEBUG o.s.web.servlet.DispatcherServlet - Exiting from "FORWARD" dispatch, status 405
2019-07-16 15:45:27 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
2019-07-16 15:45:27 ERROR o.s.b.w.s.support.ErrorPageFilter - Cannot forward to error page for request [/vouchers/uploadPdfFile] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
有什么提示吗?
预先感谢 胡安
答案 0 :(得分:0)
我找到了解决方案。因为我花了两天时间处理此问题,所以我会与社区分享它,也许这篇文章可以对某人有所帮助...
首先,该问题与CSRF的生成或发布无关。被掩盖为405错误的完全不同的问题。这是关于此问题的第一个结论:您可能会收到405错误,但可能是由于其他错误(内部服务器错误-在我的情况下为500)引起的。
我收到500错误的原因无关紧要,重要的是我得出的结论是405错误显示为500错误:我通过在Spring Boot中添加以下几行,简单地禁用了csrf令牌机制我的应用程序配置(扩展WebSecurityConfigurerAdapter的类):
http
.csrf().disable(); // this will disable the crsf token mechanism from the entire app. Be careful!!
当我禁用它时,出现500错误,这是一个非常简单的错误(百里香解析表达式错误)。我解决了500,然后再次启用csrf机制,它起作用了!
希望以后可以帮助别人。
问候 胡安
答案 1 :(得分:0)
正如 Juan 所指出的,405 错误很可能是因为 csrf 令牌。 Dropzone 在内部更改请求类型,这会导致 csrf 令牌发生变化,从而导致此异常。为了防止这种情况,您需要做的就是传递与表单中相同的 csrf 令牌。
在您的表单中添加:
meta name="_csrf" th:content="${_csrf.token}" meta name="_csrf_header" th:content="${_csrf.headerName}
并在js中添加:
init: function() {
dzClosure = this;
document.getElementById("submit-form-btn").addEventListener("click", function(e) {
e.preventDefault();
e.stopPropagation();
dzClosure.processQueue();
});
this.on("sending", function(data, xhr, formData) {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
xhr.setRequestHeader(header, token);
});
}