[TIMOB-25260] iOS: HTTPclient sends additional post request on receipt of 401 error
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Critical |
Status | Resolved |
Resolution | Cannot Reproduce |
Resolution Date | 2017-09-12T12:55:45.000+0000 |
Affected Version/s | n/a |
Fix Version/s | n/a |
Components | iOS |
Labels | httpclient |
Reporter | Ian Taylor |
Assignee | Hans Knöchel |
Created | 2017-09-10T07:53:15.000+0000 |
Updated | 2018-10-04T08:54:02.000+0000 |
Description
When making a POST request with httpClient and the resource returns a 401 error, a second POST request is being made automatically. Similar issues have previously been reported (and resolved) with Android, but not iOS.
var httpClient = Ti.Network.createHTTPClient({
onload: function(e) {
// This function is not triggered with the 401 response code
},
onerror: function(e) {
// This function is triggered with the 401 response code, but a second POST is also made
},
onreadystatechange: function(e) {
Ti.API.warn(this.readyState);
// 1
// 3
// 3
// 4
// 4
},
timeout: 2000
});
httpClient.open('POST', 'https://httpstat.us/401');
Hey there! I will move the ticket to TIMOB for further investigation, but we need some more infos from you: - Titanium SDK version? - Example endpoint? Thank you!
Ok, so after a quick investigation, here are the results: - The
readyState
= 4 isDONE
- The request is not sent twice, because: - ThereadyState
3 (LOADING
) is skipped in the event, insteadDONE
is sent - This does not happen when I log the values before they getting sent to the client, which leads to a race-condition while sending the ready-states in situations where the request finished immediately after it returns the "loading" state. - We should still fix this, but the issue would be a different then the one we investigated I would rename the ticket and description to the appropriate issue and schedule it for the next releases, but before I would be interested in your feedback to ensure we do not miss something from the initial ticket description. Thank you! *EDIT 1*: Workaround: Usee.readyState
instead ofthis.readyState
! *EDIT 2*: Proposed fix: Usedispatch_barrier_async
within the APSHTTPClient library to ensure thereadyState
property is set before the events are triggered.Thanks for the reply. I'm on the road right now so can't give you many more details right now. To elaborate though: I included the onreadystatechange only because I used it for debugging. I don't use it in production. The endpoint I'm using is a login for a web service. When I get a 401 response the onerror callback handles this. However, I can see from the web service logs that an additional request is made. Does that help?
In the onload and onerror callbacks I use this.responseText. I will try using e.responseText to see if that is a workaround.
I have tested this will multiple servers and even have set-up a local node server that received a POST request and logged it to a monitoring-console every time a new POST request was seen. That's why I came to the conclusion that either your app-logic will trigger it twice without noticing (for example with global Ti.App events not being handled correctly or recursive code in special if-statements), or your server is working not correctly and gives multiple responses. Both actually happened to me in my 7 years of Titanium / web-interaction as well, so this might be a direction to check. In any case, I will have to resolve this ticket as
Cannot Reproduce
unless we receive a full test-case that includes both the client code and and a server-URL that we can trigger.Here is the client code. I can send you the endpoint via email. var win = Ti.UI.createWindow({backgroundColor: "#fff"}); var pw = Ti.UI.createTextField({top:100,width:100,value:'adminman'}); var un = Ti.UI.createTextField({top:200,width:100,value:'adminman'}); var btn = Ti.UI.createButton({top:300,width:100,backgroundColor:'#26d045'}); btn.addEventListener('click', function(e) { if (Titanium.Network.online) { var client = Ti.Network.createHTTPClient({ onload:function(event) { Ti.API.info('onload '+this.responseText+ ' code: '+this.status); }, onerror:function(event) { Ti.API.info('onerror '+this.responseText+ ' code: '+this.status); }, timeout:2000 }); client.open('POST','endpoint'); client.setRequestHeader('Content-Type','application/json'); client.send(JSON.stringify({password:pw.value,username:un.value})); } }); win.add(btn); win.add(pw); win.add(un); win.open();
Thanks for sharing. I updated it with a test URL and formatted the source:
Which still fires the events properly and the server is only triggered once.
I am having this exact same issue in 7.1.1.GA and have narrowed down the scenario. When the server sends a 401 Unauthorized response, AND that response contains a "WWW-Authenticate" header, Appcelerator will send the request again. If the same 401 response comes back the second time, the error "cancelled" is returned. When removing the "WWW-Authenticate" header from the server response in my test app, Appcelerator behaved as expected and did not repeat the request. However, in our production instance, we are unable to remove the header from the response, so this is causing us quite a bit of grief. I have a sample Appc app, and also a small service (written in asp.net/C#) that readily produces this issue. Please reach out to me if you would like me to send this to you. I hope this allows you to reproduce and resolve this issue, and look forward to a fix. Thanks! ::Tommy
This also happens for both POST and GET... I haven't tried PUT or DELETE.
Also getting the
cancelled
response.