Итак, я искал всю эту сеть для этого, но не мог найти, почему этот не работает. Я до сих пор довольно далеко, думаю, я просто застрял в этой очень странной проблеме.Тестирование множественного/связанного запроса POST с UrlConnection - Не удалось найти границу MIME: - the_photo
Я создал веб-сервис CXF, который позволяет людям загружать фотографии (для развертывания в Google Apps Engine). Он должен работать нормально, но: я не знаю, как это проверить, поскольку он многочастен/связан (так же как и контракт). Невозможно протестировать это через PostMan, SOAPUI или любой другой тестер UI, поэтому я сразу же пошел на тестирование с Java.
Я начал из этой статьи: http://www.jguru.com/faq/view.jsp?EID=735674, и прошли через эти примеры того, как мой синтаксис должен выглядеть следующим образом:
- http://www.stylusstudio.com/xmldev/199911/post60420.html
- http://msdn.microsoft.com/en-us/library/ms527355(v=exchg.10).aspx
- https://www.ietf.org/rfc/rfc2387.txt
Heck , Я даже прошел через исходный код 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, что заставляет другой конец провода не найти границу. Но я слишком долго смотрел на это и не могу найти его.
Edit: Так, я сделал некоторые изменения:
Я добавил:
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--
Я еще получаю ту же ошибку. Может кто-нибудь объяснить мне, что я делаю неправильно?
Разрыв строки по умолчанию в поля заголовка - CRLF = "\ r \ n". Итак, здесь также: http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html#z0. –
Я просто пробовал это, но это не помогло: я добавил 'private static final String CRLF =" \ r \ n ";', а затем всегда добавлял это ко всем строкам вместо "\ n". Все еще получаю ту же ошибку ... – testuser
Я добавил свои изменения кода. Спасибо, что постарался мне помочь – testuser