Web Service call using system.net.httpClient

Hi All, my first post here. Hopefully up to standards!

I have been tasked with setting up communication with WebServices from Gateway and I have some problems sending the data.

  • The Gateway sits on industrial network,
  • I have been assured the Firewall exceptions were added,
  • *.PEM certificates were copied to gateway PC windows Certificate stores and Ignition KeyStores - the gateway was restarted.

The connection from Gateway PC was tested by standalone(vbs) script and is returning desired value from WebService.
Initially I have tried urllib2 to make a call, it is working from my laptop from corporate network but didn't from the Gateway script(I probably need to add certificates to JavaWrapper configuration?)

Since then we moved to system.net.httpClient using a simple script below(increasing/adding timeout didn't help):

from java.lang import Exception as JavaException

#logger
logger = system.util.getLogger("test")

# Credentials
username = username
password = secret

# URL to send the request to
url = "https://urlhere.com"

# XML payload as a string
xml_payload = """
<Request>
    <Item>REDACTED</Item>
</Request>
"""

# Create a dictionary with headers for XML content type
headers = {
    "Content-Type": "application/xml"
}

# Specify a timeout (in milliseconds)
timeout = 30000

# Create an HTTP client with the specified timeout and credentials
client = system.net.httpClient(timeout=timeout, username=username, password=password)

try:
    # Make a POST request with the XML payload
    response = client.post(url, data=xml_payload, headers=headers)

    # Check the response
    if response.good:
        # Log successful response
        logger.info("Successful POST to URL: %s with response status code: %s" % (url, response.statusCode))
        logger.info("Response Body: %s" % response.text)
    else:
        # Log error response
        logger.error("Error POSTing to URL: %s with response status code: %s" % (url, response.statusCode))
        logger.error("Response Body: %s" % response.text)

except JavaException as je:
    # Log Java Exception
    logger.error("Java Exception occurred while POSTing to URL: %s" % url, je)
    je.printStackTrace()

except Exception as e:
    # Log Python Exception
    logger.error("Python Exception occurred while POSTing to URL: %s" % url, e)

and this is the message from gateway logger:

java.io.IOException: Unable to POST https:/urlhere.com

at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:103)

at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.post(JythonHttpClient.java:318)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.base/java.lang.reflect.Method.invoke(Unknown Source)

at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:190)

at org.python.core.PyObject.__call__(PyObject.java:422)

at org.python.core.PyMethod.instancemethod___call__(PyMethod.java:237)

at org.python.core.PyMethod.__call__(PyMethod.java:228)

at org.python.pycode._pyx9.f$0(:144)

at org.python.pycode._pyx9.call_function()

at org.python.core.PyTableCode.call(PyTableCode.java:173)

at org.python.core.PyCode.call(PyCode.java:18)

at org.python.core.Py.runCode(Py.java:1687)

at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:804)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:843)

at com.inductiveautomation.ignition.common.script.ScriptManager.runCode(ScriptManager.java:752)

at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runCode(ProjectScriptLifecycle.java:824)

at com.inductiveautomation.ignition.common.script.TagChangeScriptExecutor$TagChangeExecutionCallback.execute(TagChangeScriptExecutor.java:242)

at com.inductiveautomation.ignition.common.script.TagChangeScriptExecutor$TagChangeExecutionCallback.execute(TagChangeScriptExecutor.java:194)

at com.inductiveautomation.ignition.common.util.SerialExecutionQueue$PollAndExecute.run(SerialExecutionQueue.java:102)

at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)

at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.base/java.lang.Thread.run(Unknown Source)

Caused by: java.net.http.HttpConnectTimeoutException: HTTP connect timed out

at java.net.http/jdk.internal.net.http.HttpClientImpl.send(Unknown Source)

at java.net.http/jdk.internal.net.http.HttpClientFacade.send(Unknown Source)

at com.inductiveautomation.ignition.common.script.builtin.http.JythonHttpClient.send(JythonHttpClient.java:101)

... 26 common frames omitted

java.net.http.HttpConnectTimeoutException: HTTP connect timed out

at java.net.http/jdk.internal.net.http.MultiExchange.toTimeoutException(Unknown Source)

at java.net.http/jdk.internal.net.http.MultiExchange.getExceptionalCF(Unknown Source)

at java.net.http/jdk.internal.net.http.MultiExchange.lambda$responseAsyncImpl$7(Unknown Source)

at java.base/java.util.concurrent.CompletableFuture.uniHandle(Unknown Source)

at java.base/java.util.concurrent.CompletableFuture$UniHandle.tryFire(Unknown Source)

at java.base/java.util.concurrent.CompletableFuture.postComplete(Unknown Source)

at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(Unknown Source)

at java.net.http/jdk.internal.net.http.Exchange.checkCancelled(Unknown Source)

at java.net.http/jdk.internal.net.http.Exchange.cancel(Unknown Source)

at java.net.http/jdk.internal.net.http.MultiExchange.cancel(Unknown Source)

at java.net.http/jdk.internal.net.http.PlainHttpConnection$ConnectTimerEvent.handle(Unknown Source)

at java.net.http/jdk.internal.net.http.HttpClientImpl.purgeTimeoutsAndReturnNextDeadline(Unknown Source)

at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(Unknown Source)

Caused by: java.net.ConnectException: HTTP connect timed out

and I am just wondering what I am missing in order to make that connection/call.
Please let me know if I can provide more information. We are on Ignition 8.1.

A connect timed out means whatever you're talking to isn't responding at all. Corporate firewall is likely to blame. Make sure there's an open tunnel between your target service and your gateway on the HTTPS port (443 unless otherwise specified).

1 Like

Thanks @PGriffith, I will forward to IT to check.

Edit:
it were the ports in the end. Thank you for your help!

1 Like

What if what I'm talking to will take 30 - 120 seconds to respond? It seems increasing that timeout doesn't allow for those long wait times.

Is the httpClient function limited?

TCP/IP itself has a standardized timeout of 90 seconds, that is pretty much constant throughout any network's infrastructure. That is the timeout that yields a connection failure at a very low OS level, like you see above. That is basically not adjustable.

If a webservice accepts the connection, but then takes a long time to respond, that's where a longer timeout in the httpClient can help.

Your network is simply not accepting the connection in the first place--it isn't a processing timeout.

Also note that connect timeout and (request) timeout are different things.

Connect timeout is establishing the connection, i.e. opening a TCP/IP socket. There is no reasonable scenario this takes 30 - 120 seconds, and isn't the same thing as some HTTP request taking an absurdly long time to have a response come back, which is what the configurable timeout is for.

1 Like

Thanks for the feedback. I actually just circumvented Ignition httpClient and created one from imports directly using these:

    # Import Java classes for custom HTTP client
    from java.net import URL, HttpURLConnection
    from java.io import BufferedReader, InputStreamReader, OutputStreamWriter
    from java.lang import StringBuilder

It was able to handle the (now) 2-3 minute wait time for a response. <- sorry, I should've mentioned that this is an AI API call and they can take a while depending on the prompt and what is being requested from it. Doing the exact same call to the AI API with system.net.httpClient does not work.

So, not the same error message as the OP? (Connect timeout)

In the future, make a new post, supplying the relevant details, when your situation doesn't match the original post.

Hence my question, I wasn't sure...which is the point of forums, to ask questions.

As far as I could tell, my situation did match. I was trying to use the httpClient and getting a HTTP connect time out in the logs. So it was a valid question which led me to my solution.

I appreciate your feedback :slight_smile: seriously I do - I know you are an expert in these topics.