- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将图片文件从我的 Android 应用程序上传到我的 JavaEE REST 服务,该服务已部署到 JBoss Wildfly 9 服务器。
我对 Content-Disposition
的理解是,它应该为每个上传的部分定义为自己的 header ,但也可以在请求 header 中定义 - 如果只上传一个文件。
所以在 header 中我定义了 Content-Type: multipart/form-data;boundary=*****
,而每个(现在只有一个 ) 部分以 --*****
开头,然后我以 --*****--
结束请求正文。这是为了防止我以后需要升级到多文件上传。
服务器应该可以从 Android 和 AngularJS 应用程序访问。因此,我为 AngularJS 应用程序添加了一个 ContainerResponseFilter
,但我看不出任何原因这应该是请求被阻止的原因。
@Override
public void filter(ContainerRequestContext requestCtx, ContainerResponseContext responseCtx)
throws IOException {
responseCtx.getHeaders().add("Access-Control-Allow-Origin", "http://localhost:8000");
responseCtx.getHeaders().add("Access-Control-Allow-Credentials", "true");
responseCtx.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
responseCtx.getHeaders().add("Access-Control-Allow-Headers", "Host, "
+ "Accept, "
+ "Origin, "
+ "Connection, "
+ "Content-Type, "
+ "Cache-Control, "
+ "Content-Length, "
+ "Accept-Encoding, "
+ "Content-Disposition");
}
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
String reqSource = "(" + servletRequest.getRemoteAddr() + ") "
+ servletRequest.getRemoteUser() + "@"
+ servletRequest.getRemoteHost() + ":"
+ servletRequest.getRemotePort();
LOGGER.trace(" :: Source :: [{}]", reqSource);
String userId = (securityContext.getUserPrincipal() != null ?
securityContext.getUserPrincipal().getName() : "unknown");
LOGGER.trace(" :: User :: [{}]", userId);
String reqUri = servletRequest.getRequestURI();
String reqType = servletRequest.getMethod();
LOGGER.trace(" :: Boundary :: [{}] - [{}]", reqUri, reqType);
}
这些过滤器是我添加的唯一与应用程序和端点之间的请求和响应交互的代码。我也试过删除这些过滤器,但没有任何运气。删除 responseFilter 会中断与 AngularJS 应用程序的通信,而删除 requestFilter 只会停止日志记录。
@POST
@Consumes({MULTIPART_FORM_DATA})
public Response createPicture(MultipartFormDataInput input) {
for (InputPart inputPart : input.getParts()) {
try {
fileController.saveFile(inputPart);
return Response.ok().build();
} catch (FileNotSavedException e) {
return Response.serverError(e.getMessage()).build();
}
}
return badRequestNullResponse();
}
上传图片代码(Android):
public static void uploadBitmap(Bitmap bitmap, String filename)
throws IOException {
URL url = new URL(URL_REST_API + FILE);
HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
httpUrlConnection.setRequestProperty("Accept", "multipart/form-data");
httpUrlConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
// EDIT 2: This following log statement was omitted in the first post.
// I extracted the setRequestProperty statements from another method
// due readability of this question, but I had missed to copy this:
Log.e(LOG_TAG, "Headers: \n" + httpUrlConnection.getHeaderFields());
DataOutputStream request = new DataOutputStream(httpUrlConnection.getOutputStream());
// Part [start]
request.writeBytes(DOUBLE_HYPHEN + BOUNDARY + CR_LF);
request.writeBytes("Content-Disposition: form-data;filename=\"" + filename + "\"" + CR_LF);
request.writeBytes(CR_LF);
// Part [content]
bitmap.compress(Bitmap.CompressFormat.JPEG, IMAGE_QUALITY_PERCENTAGE, request);
// part [end]
request.writeBytes(CR_LF);
request.writeBytes(DOUBLE_HYPHEN + BOUNDARY + DOUBLE_HYPHEN + CR_LF);
request.flush();
request.close();
httpUrlConnection.disconnect();
}
如前所述,我以双连字符、边界和换行符开始“每个”部分。由于 header 是由 setRequestProperty
创建的,因此我假设 header 已正确结束。那么是不是尸体失踪造成的呢?为什么 Content-Disposition
或图片文件没有写入请求?
07:55:28,479 WARN [org.apache.james.mime4j.parser.MimeEntity] (default task-36) Unexpected end of headers detected. Higher level boundary detected or EOF reached.
07:55:28,479 WARN [org.apache.james.mime4j.parser.MimeEntity] (default task-36) Invalid header encountered
07:55:28,479 WARN [org.apache.james.mime4j.parser.MimeEntity] (default task-36) Body part ended prematurely. Boundary detected in header or EOF reached.
07:55:28,479 WARN [org.jboss.resteasy.core.ExceptionHandler] (default task-36) Failed executing POST /file: org.jboss.resteasy.spi.ReaderException: java.lang.RuntimeException: Could find no Content-Disposition header within part
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:183)
at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:89)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:112)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:296)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:250)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:237)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: Could find no Content-Disposition header within part
at org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInputImpl.extractPart(MultipartFormDataInputImpl.java:68)
at org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl.extractParts(MultipartInputImpl.java:229)
at org.jboss.resteasy.plugins.providers.multipart.MultipartInputImpl.parse(MultipartInputImpl.java:198)
at org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataReader.readFrom(MultipartFormDataReader.java:52)
at org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataReader.readFrom(MultipartFormDataReader.java:20)
at org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataReader$Proxy$_$$_WeldClientProxy.readFrom(Unknown Source)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.readFrom(AbstractReaderInterceptorContext.java:59)
at org.jboss.resteasy.core.interception.ServerReaderInterceptorContext.readFrom(ServerReaderInterceptorContext.java:62)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:51)
at org.jboss.resteasy.security.doseta.DigitalVerificationInterceptor.aroundReadFrom(DigitalVerificationInterceptor.java:32)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:53)
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor.aroundReadFrom(GZIPDecodingInterceptor.java:59)
at org.jboss.resteasy.plugins.interceptors.encoding.GZIPDecodingInterceptor$Proxy$_$$_WeldClientProxy.aroundReadFrom(Unknown Source)
at org.jboss.resteasy.core.interception.AbstractReaderInterceptorContext.proceed(AbstractReaderInterceptorContext.java:53)
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:150)
... 38 more
还有;我发现了一些关于 WFLYWELD0052: (...) Package-private access will not work.
的 WARN 消息,所以我通过添加 core
和 spi
来解决这些问题> 作为警告模块中的依赖项,如 suggested in this issue .它删除了警告消息,但没有解决问题。
这是来自 android 应用程序的上传请求的日志,我在其中打印随请求发送的 header :
(default task-42) Header: [Accept]
(default task-42) Value: [multipart/form-data]
(default task-42) Header: [Cache-Control]
(default task-42) Value: [no-cache]
(default task-42) Header: [Connection]
(default task-42) Value: [Keep-Alive]
(default task-42) Header: [User-Agent]
(default task-42) Value: [Dalvik/2.1.0 (Linux; U; Android 5.0.2; SM-A500FU Build/LRX22G)]
(default task-42) Header: [Host]
(default task-42) Value: [***.**.***.***:8080]
(default task-42) Header: [Accept-Encoding]
(default task-42) Value: [gzip]
(default task-42) Header: [Content-Length]
(default task-42) Value: [0]
(default task-42) Header: [Content-Type]
(default task-42) Value: [multipart/form-data;boundary=*****]
(default task-42) :: Source :: [(*.***.**.**) null@*.***.**.**:28686]
(default task-42) :: User :: [unknown]
(default task-42) :: Boundary :: [/upload/api/file/] - [POST]
(default task-42) Unexpected end of headers detected. Higher level boundary detected or EOF reached.
(default task-42) Invalid header encountered
(default task-42) Body part ended prematurely. Boundary detected in header or EOF reached.
通过 Postman 上传时,我能够按预期访问终点 - 除了添加文件之外(也许 Postman 会自动创建内容处置标签?)。
我已经根据错误原因更新了 Android 代码(参见 Edit 2
-comment)。它实际上是导致错误行为的日志语句。我会添加一个答案来解释原因!
最佳答案
发生这种情况的原因是我添加了一条日志语句,用于验证发送到服务器的 header 。在我最初的问题中,这被省略了,因为以下内容最初是从另一种方法中提取的。当我从这个方法中复制代码 fragment 时,我没有想到日志语句与问题相关。
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
httpUrlConnection.setRequestProperty("Accept", "multipart/form-data");
httpUrlConnection.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + BOUNDARY);
以下行也在提取的方法中,导致了问题。
Log.e(LOG_TAG, "Headers: \n" + httpUrlConnection.getHeaderFields());
为什么你之前没有注意到这一点?
uploadBitmap
方法只是抛出 IOException
并且调用方方法只是吞下异常并打印出“无法上传图片;服务器响应 406”。这种糟糕的异常处理让我过于专注于认为服务器导致了问题。
到底发生了什么?
我在Android应用程序中错过的异常消息是cannot write request body after response has been read
,这让我查看了每一行代码,直到我发现日志语句尝试阅读标题。
为什么会导致错误?
我不是 100% 确定真正的原因,但我可以想象从连接中读取信息会告诉服务器;
“我想对你说的话已经说完了,现在我想知道你要对我说什么”。
因此,当我在写入 header 后从连接中读取时,似乎我基本上是在发送请求以获取响应。这会导致服务器无法找到 Content-Disposition
的错误,因为从来没有任何 Content-Dispositions、部分甚至主体供服务器处理。
再一次;我对此不是 100% 肯定,因为我还没有查过。
好吧,在这个错误上浪费了太多时间之后,我发现我应该更加了解我的日志语句。我也应该停止使用日志语句来获取我可以通过简单、简单的调试轻松获取的值。
关于android - 在部分中找不到 Content-Disposition header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38747908/
我在使用 io-ts 时遇到一些问题。我发现它确实缺乏文档,我取得的大部分进展都是通过 GitHub issues 取得的。不,我不明白 HKT,所以没有帮助。 基本上,我在其他地方创建一个类型,ty
我必须创建一个正则表达式来搜索整个文件,以找到与 Java XML 解析器的第一部分(但不是第二部分)的匹配项。这将用于防止某些 XXE 攻击。不幸的是,它确实必须是单个正则表达式,并且它确实需要搜索
我有一些简单的 Shared/_Header.cshtml 文件中的内容。 My Shared/_Layout.cshtml 通过调用插入该代码 @Html.Partial("_Header") 目前
我有一个 if-else 语句,其中: 条件 1:ID 匹配并且自动填充某些字段。然后 if 语句只填充其余字段 条件 2:ID 不匹配,所有字段均为空白。 ELSE 语句将它们全部填充 当我使条件
我正在开发一个单页滚动网站。我正在尝试实现 ScrollMagic 并固定第一部分,以便网站的其余部分滚动到固定部分的顶部。我尝试创建一个 jsfiddle 来显示问题,但我似乎无法让 jsfiddl
这是我的情况: 我想使用 Google AdWords 的转换脚本,但出于某种原因,他们代码段的 javascript 部分在我的页面上添加了一些我似乎无法摆脱的不需要的空白。 所以我正在查看的选项纯
寻找一种优雅的方式在页面上添加一次脚本,就是这样。 我有一个需要 2 个 CSS 文件和 2 个 JS 文件的部分 View 。在大多数地方,只需要其中 1 个部分 View 。但在单个页面上,我需要
我想要一个网站,该网站始终具有相同的部分,具有相同的 id 以及我想要显示的所有内容。我对 javascript 不太了解,我想知道如何删除除特定部分之外的所有内容。 最好的方法是否是只执行一个循环来
SQL 语句教程 (11) Group By 我们现在回到函数上。记得我们用 SUM 这个指令来算出所有的 Sales (营业额)吧!如果我们的需求变成是要算出每一间店 (store_name)
我试图理解部分并认为我已经明白了。基本上,这是一种将部分应用程序应用于二元运算符的方法。所以我了解所有(2*) , (+1)等例子就好了。 但是在 O'Reilly Real World Haskel
有没有办法禁止在部分中覆盖给定的关键字参数?假设我要创建函数 bar总是有 a设置为 1 .在以下代码中: from functools import partial def foo(a, b):
我有这个使用节的 OpenMP 代码 #pragma omp parallel sections num_threads(8) { printf_s("Allo fro
我正在尝试重新创建 Apple 制作的有缺陷的 CNContactPickerViewController,因此我有一个数据数组 [CNContact],我需要将其整齐地显示在 UITableView
我有一个相对布局,其中包含一些 float 在 GridView 上的 TextView 。当我在网格中选择一个项目时,布局向下移动到屏幕的尽头,只有大约 1/5 的部分是可见的。这是使用简单的翻译动
我想在我的 tableView 中有两个部分。我希望将项目添加到第 0 节,然后能够选择一行以将其从第 0 节移动到第 1 节。到目前为止,我已将这些项目添加到第 0 节,但是当它关闭时数据不会加
我正在以自由职业者的身份开发支付控制软件,但我有一些关于 mysql 的问题。 。我有一个用作日志的表,名为“Bitacora”。在表中,我有一个名为 idCliente 的列,它是自己表中一个人的
我有一个 PFQueryTableViewController,我想向 tableview 添加部分,我这样尝试: - (PFQuery *)queryForTable { PFQuery *qu
我正在尝试编写一个查询,将部分匹配项与存储的名称值进行匹配。 我的数据库如下所示 Blockquote FirstName | Middle Name | Surname --------------
我正在开发一个语音备忘录应用程序,并且正在将文件保存到表格 View 中。我希望默认文件名显示为“新文件 1”,如果使用“新文件 1”,则它会显示为“新文件 2”,依此类推。 我正在尝试使用 do-w
我有以下简单的 HTML 布局 .section1 { background: red; } .section2 { background: green; } .section3 { ba
我是一名优秀的程序员,十分优秀!