I am continuously posting data to server using Java with Apache fluent api.
Content content = Request.Post(URL)
.bodyForm(param)
.execute()
.returnContent();
The above works perfectly but after some random execution time I am getting org.apache.http.NoHttpResponseException: failed to respond. How I can handle this to post the same parameter again after getting this exception.
EDIT
Ok, I have to handle response, something like this but still don't have any clue how this can be done.
Content content = Request.Post(URL)
.bodyForm(param)
.execute().handleResponse(new ResponseHandler<Content>() {
public Content handleResponse(HttpResponse arg0)
throws ClientProtocolException, IOException {
// TODO Auto-generated method stub
return null;
}
});
Instead of using fluent API I used the following below method and overcome my own problem:-
get NoHttpResponseException for load testing
Apache HttpClient Interim Error: NoHttpResponseException
Related
I'm calling a remote web service and am occasionally getting the following error:-
Error caught: com.sun.xml.internal.ws.server.UnsupportedMediaException: Unsupported Content-Type: text/plain;charset=ISO-8859-1 Supported ones are: [text/xml]
Does anyone know how to get the actual message that was returned by the server? It sounds like it might be text or a web page but I'm unable to get it.
I can catch the UnsupportedMediaException but I don't know what to do to extract the actual response. Here's the code:-
val selectedDate = exchange.`in`.getHeader("selectedDate").toString()
val accountNumberMinor = exchange.`in`.getHeader("accountNumberMinor").toString()
val accountNumberMajor = exchange.`in`.getHeader("accountNumberMajor").toString()
val accountIdentifier = if (accountNumberMinor.trim() != "") accountNumberMinor else accountNumberMajor
val effectiveDate = SimpleDateFormat("yyyy-MM-dd").parse(selectedDate)
val response = webRequest.getResponse(accountIdentifier, selectedDate)
val result = response.result as FixedIncomeCurrencyForwardAccountV10Result
Thanks,
Adam
An HTML page is usually a server error yes. Probably a static service page (like 404 or 5xx). It could even be an error in your request that should be returned as a SOAPFault, but is not implemented as such by the specific server.
Sometimes the server does communicate a valid SOAP (Fault) message, but the content type header is just wrong. In that case you're better off rewriting the Content-Type from the response with a proxy server. See for references on this subject:
SOAP unsupported media exception text/plain Supported ones are: [text/xml]
So, what can you do to view the HTML content?
With JAX-WS you can enable all HTTP web service traffic to be logged to System.out with the following vm options:
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=TRUE
-Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dump=TRUE
-Dcom.sun.xml.internal.ws.transport.http.HttpAdapter.dumpTreshold=999999
See for references:
https://www.rgagnon.com/javadetails/java-logging-with-jax-ws.html
https://www.javatips.net/api/com.sun.xml.ws.transport.http.client.httptransportpipe
Now, this will dump all http requests and responses, but you might only be interested in the ones where you don't get soap/xml.
So, what else can you do?
You could set these options programmatically and re-send the request when you catch the UnsupportedMediaException. But in the time this takes the error might have disappeared. Note that these properties are cached, so setting them needs to go through com.sun.xml.ws.transport.http.client.HttpTransportPipe#setDump(Boolean)
If you're willing to switch to the JAX-WS runtime, you could also create your own com.sun.xml.ws.api.pipe.TransportTubeFactory since jaxws-rt can load custom instances of this factory. I have successfully created my own TransportTubeFactory that uses a custom com.sun.xml.ws.transport.http.client.HttpTransportPipe (by extending it and overriding processRequest) that reads the http response from the com.sun.xml.ws.api.pipe.Codec upon catching the UnsupportedMediaException. By wrapping the Codec you can store the input stream on the decode method call.
This runtime is nearly identical to the internal runtime, and should be fully compatible.
This may also work with the internal classes from the Java runtime, but since those are located in RT.jar it's difficult to depend on it and build your project. So i would advice switching to the external JAX-WS runtime.
What you then do with the input stream is up to you (which is the body of the HTTP response at the moment of catching the UnsupportedMediaException).
Note that you can also rewrite most* content type headers in code with this codec wrapper.
See for reference how to add your own implementation of this factory via META-INF/services here:
https://www.javadoc.io/doc/com.sun.xml.ws/jaxws-rt/latest/com.sun.xml.ws/com/sun/xml/ws/api/pipe/TransportTubeFactory.html
In short:
Create a file in META-INF/services called com.sun.xml.ws.api.pipe.TransportTubeFactory
The contents of this file should be a single line with the full class name of your custom factory, for example my.soap.transport.MyTransportTubeFactory
Note; if you're using the classes from the Java runtime instead of jaxws-rt, use com.sun.xml.internal.ws as the package for everything in this post that references com.sun.xml.ws.
*Note: newer versions of this runtime (jaxws-rt-2.3.x or jre 8+ internal) throw a different exception on text/html responses. Sadly before calling Codec.decode. So in that case you would have to copy more code into your custom HttpTransportPipe. text/plain currently still works though.
Some snippets of my code:
public class TransportTubeFactoryImpl extends TransportTubeFactory {
#Override
public Tube doCreate(ClientTubeAssemblerContext context) {
String scheme = context.getAddress().getURI().getScheme();
if (scheme != null) {
if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
CodecWrapper codec = new CodecWrapper(context.getCodec());
return new HttpTransportPipeImpl(codec, context.getBinding());
}
}
throw new WebServiceException("Unsupported endpoint address: " + context.getAddress());
}
}
public class CodecWrapper implements Codec {
private Codec wrapped;
public CodecWrapper(Codec wrapped) {
this.wrapped = wrapped;
}
#Override
public void decode(InputStream in, String contentType, Packet response) throws IOException {
copyInputStream(in); // todo: implement this
wrapped.decode(in, contentType, response);
}
}
public class HttpTransportPipeImpl extends HttpTransportPipe {
private CodecWrapper codec;
public HttpTransportPipeImpl(CodecWrapper codec, WSBinding binding) {
super(codec, binding);
this.codec = codec;
}
#Override
public NextAction processRequest(Packet request) {
try {
return super.processRequest(request);
} catch (UnsupportedMediaException ex) {
// todo: here you can access the stored data from the codec wrapper
}
}
}
I have also created a complete working demonstration of this principle on my github: https://github.com/s-lindenau/SoapContentTypeDemo
If you still have the option to switch to a completely different client library, you could also check Apache CXF:
How can I make jaxws parse response without checking Content-Type header
I am using the following code to update a confluence page:
public void publish() throws IOException {
XWikiXmlRpcClient rpc = new XWikiXmlRpcClient(CONFLUENCE_URI);
try {
rpc.login(USER_NAME, PASSWORD);
//The info macro would get rendered an info box in the Page
Page page = new Page();
page.setSpace("ATF");
page.setTitle("New Page");
page.setContent("New Page Created \\\\ {{info}}This is XMLRPC Test{{/info}}");
page.setParentId("demo UTF Home");
rpc.storePage(page);
} catch (XmlRpcException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I try to run the program, I get the following exception:
org.apache.xmlrpc.client.XmlRpcClientException: Failed to parse server's response: Expected methodResponse element, got html
This looks like a bug in Apache xml-rpc client going by this JIRA:
https://issues.apache.org/jira/browse/XMLRPC-159
It says it was fixed in 3.1.2 of the library, I am using 3.1.3.
Anyone seen this before?
Maybe the server really returned HTML; sometimes it simply returns a 200 because something is there that always produces HTML. In that case the bugfix in the XMLRPC-library you have linked to does not apply.
To check for this possibility, you can look into the server access logs for the url of the request and the status code (should be a 200); with this information you can replay the request e.g. in a browser or command line client like wget or curl, and see what is really returned as response.
I am writing a REST application using Tomcat and Spring WebMVC.
I want to signal errors to my client using HTTP status codes along with some XML payload that contains more information about what went wrong.
To catch all errors regardless of where they occur, I have written a Filter which wraps the response and overrides the sendError() method:
private static final class GenericErrorResponseWrapper
extends HttpServletResponseWrapper
{
#Override
public void sendError(int sc, String msg) throws IOException {
final HttpServletResponse wrappedResponse = (HttpServletResponse) getResponse();
wrappedResponse.setStatus(sc, msg);
wrappedResponse.setContentType("application/xml");
PrintWriter writer = wrappedResponse.getWriter();
try {
SimpleXmlWriter xmlWriter = SimpleXmlWriterWrapper.newInstance(writer);
xmlWriter.writeStartElement("ns2", "genericError")
.writeAttribute("xmlns:ns2", "http://mynamespace")
.writeCharacters(msg)
.writeEndDocument().flush();
writer.flush();
wrappedResponse.flushBuffer();
} finally {
writer.close();
}
}
}
This implementation has two problems:
It generates a deprecation warning in Eclipse, since HttpServletResponse.setStatus(sc, msg) is deprecated.
The HTTP response header generated by Tomcat is not correct, it starts with the first line "HTTP/1.1 500 OK". 500 is correct, but instead of OK the reason phrase should be "Internal Server Error".
How can I implement my filter so that it does the right thing and is free of deprecation warnings? Both alternatives named in the Javadoc are not usable for me:
sendError(sc, msg) is not usable, since it commits the response body and I can't write XML payload any more
setStatus(sc) with just the error code is theoretically usable, but it also creates the hardcoded "OK" string in the first line of the response header.
There is unfortunately no way to avoid the deprecation warning. As you already mention yourself, the two alternatives which are referred to in the API documentation do not cover the same functionality. You may of course annotate your method with #SuppressWarnings("deprecation") to indicate that the usage of the deprecated method is intended.
The other thing, that Tomcat does not use your message string, even if one is provided, is a configuration issue. For some strange reason, Tomcat will by default ignore the provided message string and use a default error message based on the passed return code. You must set the system property org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER to true to force Tomcat to use your provided error message instead. More details on this can be found in the Tomcat documentation.
As an alternative answer - you could first write the XML payload, without calling flush/flushBuffer, and only after that do sendError(int, String), which would flush the buffer.
I have developed a REST service using Apache CXF and notice that if I send invalid characters in the URL, the CXF servlet throws back the following exception before it gets to my code:
Servlet failed with Exception
java.lang.IllegalArgumentException
at java.net.URI.create(URI.java:841)
at org.apache.cxf.transport.servlet.BaseUrlHelper.getBaseURL(BaseUrlHelper.java:49)
at org.apache.cxf.transport.servlet.ServletController.getBaseURL(ServletController.java:73)
at org.apache.cxf.transport.servlet.ServletController.updateDestination(ServletController.java:82)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:162)
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:137)
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:158)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:239)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:164)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:215)
This results in a 500 status code being returned to the client.
I would ideally like to intercept this exception and return a 400 Bad Request status code to the client but I am unable to work out how to do this.
Any help much appreciated!
Many thanks
The way I did this is by means of an interceptor.
If an error has occurred during initial processing of a request, a framework response (and of course status code) will be put on the message pipe.
So you could for example write a interceptor on "marshall" phase, check if there already is a response and rewrite to your own response.
#Override
public void handleMessage(Message message) throws Fault {
if (message.getExchange().get(Response.class) != null) {
//build your response and put it on the exchange
message.getExchange().put(Response.class, yourResponse);
}
I am using netbeans as an IDE to give you an indication of background.
I am playing around with the Apache httpclient library as in my current app I am having issues with the in built java HTTP connection.
I heard that the apache library was more powerful.
Anyway, the tutorial documentation that comes with the httpclient library on the apache site seems to be flawed:
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://localhost/");
HttpResponse response = httpclient.execute(httpget);
Net beans gives me issues with this code snippet (copied straight from the tutorial). Forget even the rudimentary URI of localhost, problems that arise with this are:
netbeans complains that HttpClient and DefaultHttpClient are incompatible types. The only way I can see around this is to cast with:
(HttpClient) new DefaultHttpClient();
Netbeans complains that the httpclient.execute() would throw an error because "httpget" here is simply a method and not a "HttpUriRequest".
How can a simple 3 line tutorial be so wrong and how would I actually successfully complete a request if there is so many flaws in this example?
I'm lost, can someone help. There seems to be several different ways, all not entirely what I'm looking for.
I want to be able to take a well-formed URL that I already have in the app in String, and then follow-all redirects. I'm not at all interested in the contents of the response, merely the cookies that it will drop.
Thanks,
Gregory
I suggest looking at your imports. I think NetBeans imported your HttpClient 3.x instead of 4.x. Try correcting your imports.
Have you tried using this code, they seem to use different mechanisms than you do. Taken from here. This is for the 3.X version though so it might be that you are using a different version.
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.params.HttpMethodParams;
import java.io.*;
public class HttpClientTutorial {
private static String url = "http://www.apache.org/";
public static void main(String[] args) {
// Create an instance of HttpClient.
HttpClient client = new HttpClient();
// Create a method instance.
GetMethod method = new GetMethod(url);
// Provide custom retry handler is necessary
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler(3, false));
try {
// Execute the method.
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: " + method.getStatusLine());
}
// Read the response body.
byte[] responseBody = method.getResponseBody();
// Deal with the response.
// Use caution: ensure correct character encoding and is not binary data
System.out.println(new String(responseBody));
} catch (HttpException e) {
System.err.println("Fatal protocol violation: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("Fatal transport error: " + e.getMessage());
e.printStackTrace();
} finally {
// Release the connection.
method.releaseConnection();
}
}
}
When I used this (on Android) I implemented a CustomHttpClient, following the example here