所以,我搜索了整个网络,但是找不到为什么这个不起作用。到目前为止,我已经相当远了,我想,我只是坚持这个目前非常奇怪的问题。
我已经构建了一个CXF网络服务,允许人们上传照片(将部署在Google Apps Engine中)。它应该工作正常,但是:我不知道如何测试它,因为它是多部分/相关的(合同也是如此)。无法通过PostMan,SOAPUI或任何其他UI测试程序对此进行测试,因此我直接从Java进行测试。
我从这篇文章开始:http://www.jguru.com/faq/view.jsp?EID=735674,并详细介绍了我的语法应该是这样的示例:
哎呀,我甚至通过Apache CXF的源代码来查找崩溃的来源GC - AttachmentDeserializer。
这是想要发送的内容:
--the_photo
Content-Type: application/json
{
"objectToLinkTo": "ad9821e6-d308-472b-b21f-308b08c3fa70"
}
--the_photo
Content-Type: image/jpeg
JPEG data
--the_photo--
这是我尝试发送此内容的方法:
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Paths;
public class PhotoTest {
private static final String ADD_PHOTO = "http://localhost:8080/v1/photos";
private static void writeJson(String value, DataOutputStream out, String boundary) {
try {
out.writeBytes("Content-Type: application/json");
out.writeBytes("\n{'objectToLinkTo': '" + value + "'}");
out.writeBytes("\n--" + boundary);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void writeImage(String contentType, String file, DataOutputStream out, String boundary) {
try {
out.writeBytes("Content-Type: " + contentType + "\n");
java.nio.file.Path path = Paths.get(file);
byte[] data = Files.readAllBytes(path);
out.write(data);
out.writeBytes("\n--" + boundary + "--");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main (String args[]) {
try {
URL servlet = new URL(ADD_PHOTO);
URLConnection urlConnection = servlet.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.setUseCaches(false);
String boundary = "the_photo";
urlConnection.setRequestProperty("Content-type", "multipart/related; boundary=" + boundary);
urlConnection.setRequestProperty("Cache-Control", "no-cache");
DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
out.writeBytes("--" + boundary + "\n");
writeJson("ad9821e6-d308-472b-b21f-308b08c3fa70", out, boundary);
writeImage("image/jpeg", "K:\\Downloads\\test.jpg", out, boundary);
out.flush();
out.close();
InputStream stream = urlConnection.getInputStream();
BufferedInputStream in = new BufferedInputStream(stream);
int i = 0;
while ((i = in.read()) != -1) {
System.out.write(i);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务器端的结果(使用mvn appengine:test
在本地部署代码):
[INFO] 07:27:06,804 ERROR [commons.exceptions.exceptionwrapper.RuntimeExceptionWrapper] - Couldn't find MIME boundary: --the_photo
[INFO] org.apache.cxf.interceptor.Fault: Couldn't find MIME boundary: --the_photo
[INFO] at org.apache.cxf.interceptor.AttachmentInInterceptor.handleMessage(AttachmentInInterceptor.java:60)
[INFO] at org.apache.cxf.jaxrs.ext.MessageContextImpl.createAttachments(MessageContextImpl.java:267)
[INFO] at org.apache.cxf.jaxrs.ext.MessageContextImpl.get(MessageContextImpl.java:76)
[INFO] at org.apache.cxf.jaxrs.impl.tl.ThreadLocalMessageContext.get(ThreadLocalMessageContext.java:38)
[INFO] at org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getMultipartBody(AttachmentUtils.java:114)
[INFO] at org.apache.cxf.jaxrs.utils.multipart.AttachmentUtils.getAttachments(AttachmentUtils.java:119)
[INFO] at org.apache.cxf.jaxrs.provider.MultipartProvider.readFrom(MultipartProvider.java:151)
[INFO] at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1325)
[INFO] at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1276)
[INFO] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:815)
[INFO] at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:778)
[INFO] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212)
[INFO] at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.handleMessage(JAXRSInInterceptor.java:77)
[INFO] at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
[INFO] at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
[INFO] at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:243)
[INFO] at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:223)
[INFO] at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:197)
[INFO] at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:149)
[INFO] at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:171)
[INFO] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:286)
[INFO] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:206)
[INFO] at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
[INFO] at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:262)
[INFO] at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
[INFO] at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
[INFO] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
[INFO] at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
[INFO] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[INFO] at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
[INFO] at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
[INFO] at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
[INFO] at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
[INFO] at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
[INFO] at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
[INFO] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[INFO] at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:491)
[INFO] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[INFO] at org.mortbay.jetty.Server.handle(Server.java:326)
[INFO] at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
[INFO] at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
[INFO] at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
[INFO] at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
[INFO] at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
[INFO] at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
[INFO] at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
[INFO] Caused by: java.io.IOException: Couldn't find MIME boundary: --the_photo
[INFO] at org.apache.cxf.attachment.AttachmentDeserializer.initializeRootMessage(AttachmentDeserializer.java:123)
[INFO] at org.apache.cxf.attachment.AttachmentDeserializer.initializeAttachments(AttachmentDeserializer.java:92)
[INFO] at org.apache.cxf.interceptor.AttachmentInInterceptor.handleMessage(AttachmentInInterceptor.java:58)
[INFO] ... 58 more
所以,我很确定我在主函数中用来测试的代码甚至没有超过第一个out.writeBytes("--" + boundary + "\n");
,因为错误表明服务器代码不能在任何地方找到边界。我认为是因为我走过的GrepCode代码 - 它是在AttachmentInInterceptor中的某个地方初始化消息,代码崩溃了;因此他甚至不会将任何实际写入的数据处理到流中。 (或者:服务器永远不会到达我自己的服务器代码,它会检查两个附件,等等。)
DataOutputStream out = new DataOutputStream(urlConnection.getOutputStream());
out.writeBytes("--" + boundary + "\n");
writeJson("ad9821e6-d308-472b-b21f-308b08c3fa70", out, boundary);
writeImage("image/jpeg", "K:\\Downloads\\test.jpg", out, boundary);
out.flush();
out.close();
这里的任何人都可以帮助我吗?我究竟做错了什么?可能这只是我在urlConnection上写错了的一个细节,导致导线的另一端无法找到边界。但是我一直在寻找这个问题并且找不到它。
编辑:所以,我做了一些改变:
我补充说:
private static final String CRLF = "\r\n";
private StringBuilder text = new StringBuilder();
改变了:
public void writeJson(String value) {
String s = "--" + boundary + CRLF;
s += "Content-Type: application/json" + CRLF + CRLF;
s += "{\"objectToLinkTo\":\"" + value + "\"}" + CRLF + CRLF;
text.append(s);
}
public void writeBinaryFile(String fileName, String mimeType, String encoding) throws Exception {
String s = "--" + boundary + CRLF;
s += "Content-Type: " + mimeType + CRLF;
text.append(s);
java.nio.file.Path path = Paths.get(fileName);
byte[] data = Files.readAllBytes(path);
text.append(new String(data, encoding)).append(CRLF);
}
public void finish() {
text.append("--").append(boundary).append("--").append(CRLF);
}
private static void printResponse(URLConnection urlConnection) {
try {
InputStream is = urlConnection.getInputStream();
while (is.available() != 0) {
byte[] data = new byte[is.available()];
is.read(data);
System.out.println(new String (data, "UTF-8"));
}
} catch (Exception exc) {
exc.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
PhotoTest photoTest = new PhotoTest();
photoTest.writeJson("ad9821e6-d308-472b-b21f-308b08c3fa70");
//photoTest.writeBinaryFile("K:\\Downloads\\test.jpg", "image/jpeg", "UTF-8");
photoTest.finish();
System.out.println(photoTest.getText());
URL url = new URL(MEDIA_ADD_PHOTO);
URLConnection urlConnection = url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setUseCaches(false);
((HttpURLConnection) urlConnection).setRequestMethod("POST");
urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
urlConnection.setRequestProperty("Content-Type", "multipart/related; boundary=" + photoTest.getBoundary());
urlConnection.setRequestProperty("Content-Length", Integer.toString(photoTest.getLength()));
OutputStream output = urlConnection.getOutputStream();
output.write(photoTest.getContent().getBytes());
output.flush();
output.close();
printResponse(urlConnection);
}
现在,我删除了图像部分(只是为了检查我是否可以通过拦截器到达我自己的服务器代码,这应该检查图像是否存在)。如你所见,我打印了为控制台构建的消息,它给了我这个:
--the_photo
Content-Type: application/json
{"objectToLinkTo":"ad9821e6-d308-472b-b21f-308b08c3fa70"}
--the_photo--
我仍然得到同样的错误。谁能解释一下我做错了什么?
答案 0 :(得分:1)
好吧,正如我想的那样,它最终成了某个小错误。
我随机开始编辑内容 - 我实际上想尝试调试整个事情,但由于我从未到达我自己的服务器端代码并陷入Apache CXF层,我不能。然后我想,让我们简单地评论拦截器:
<jaxrs:server address="/v1/photos">
<jaxrs:serviceBeans>
<ref bean="resourceV1" />
</jaxrs:serviceBeans>
<!--<jaxrs:inInterceptors>-->
<!--<bean class="org.apache.cxf.interceptor.AttachmentInInterceptor"/>-->
<!--</jaxrs:inInterceptors>-->
<jaxrs:features>
<cxf:logging />
</jaxrs:features>
<jaxrs:providers>
<bean class="commons.exceptions.exceptionwrapper.BusinessExceptionWrapper" />
<bean class="commons.exceptions.exceptionwrapper.RuntimeExceptionWrapper" />
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
神奇地说:它现在有效。我不知道为什么我开始使用AttachmentInInterceptor
。
感谢您的帮助。