Can %Net.HttpRequest objects get reused (behind our back)?
We are calling a REST web-service from Ensemble using EnsLib.HTTP.OutboundAdapter
and redefining the adapter class to set custom headers as described by @Eduard Lebedyuk here: How to set Content-Type
During development we accidentally stumbled across puzzling behaviour - we now suspect that the %Net.HttpRequest
object created in the linked example is being reused in the following scenario:
- request is created as described and sent to web-service, so an instance of a
%Net.HttpRequest
object exists and is known to theEnsLib.HTTP.OutboundAdapter
- we modify our code to test what happens if headers are not set - eg changing the "GetRequest()" method in the above example to return
""
rather than a new%Net.HttpRequest
object - but in a subsequent call the headers set in step 1 above arrive in the web-service, even though they were not set (unset?) at step 2...
After really scratching our heads our suspicion is that the %Net.HttpRequest
object created in step 1 is not thrown away after use, but "remembered"/re-used by the OutboundAdapter
. Are we correct?
Is this what stands behind the "In normal use you create a single %Net.HttpRequest object and use it to issue as many requests as you need to the web server, each %Net.HttpRequest object can be thought of as a single instance of an internet browser" and "Reset the %Net.HttpRequest class so that it can issue another request. This is much faster than closing this object and creating a new %Net.HttpRequest object" in the class documentation? And if we are correct, is there documentation or good practice guidelines on how long it is wise to keep reusing such a request object? Or is it so situation dependent its impossible to say?
(Our situation is a passing a feed of healthcare data to a downstream system within our internal network; headers to contain content type and Basic Authentication headers - will only change a couple of times a year if the password is changed - and sent over the wire using SSL. We'll process several hundred, perhaps a few thousand, messages per day, mostly during working hours, with significant spikes of activity at certain points in the day.)
In the main method of
EnsLib.HTTP.OutboundAdapter
-SendFormDataArray
line 5 you can see the following code:#; Create an Http Request Object Set tHttpRequest=$S($$$IsdefObject(pHttpRequestIn):pHttpRequestIn,1:##class(%Net.HttpRequest).%New()) $$$ASSERT($IsObject(tHttpRequest)&&tHttpRequest.%IsA("%Net.HttpRequest"))
Which creates a new empty
%Net.HttpRequest
object, unlesspHttpRequestIn
(3rd arg) has been passed with a custom request object. Most wrapper methods (VERB
,VERBURL
andVERBFormDataArray
) do not passpHttpRequestIn
so you should get a fresh request object every time, butSendFormData
andSendFormDataURL
would passpHttpRequestIn
from caller, if given.Another place to look into is a
Send
call:Set tSC=tHttpRequest.Send($ZCVT(pOp,"U"),$G(pURL,..URL),..#DEBUG)
It has the following signature:
Method Send(type As %String, location As %String, test As %Integer = 0, reset As %Boolean = 1) As %Status
reset
arg defaults to1
, and when it's true theReset
method of%Net.HttpRequest
is called after every request.Reset
method removes headers (among other things). As you can see in the implementation:Kill i%Headers,i%FormData,i%Params
EnsLib.HTTP.OutboundAdapter
never callsSend
withreset=0
, so the request should be reset every time.That said, how do you call
SendFormDataArray
?I took a look at the article you linked to. Can you add logging to
GetRequest
method? It should be called on every business operation message.Thanks @Eduard Lebedyuk , that was helpful. As you describe, headers are not re-used from a previous call. On closer inspection, our confusion arose from the fact that if you provide a set of credentials as a setting on the operation which is implemented by
EnsLib.HTTP.OutboundAdapter
, even if you don't explicitly set the Basic Authentication headers yourself, they are created for you by the adapter using the provide credentials - we didn't realise this, and so when we removed our own explicit setting of the headers (for testing) we were confused by the headers still arriving in the downstream system!!