Ik heb een Android app geschreven waarmee mensen kunnen inloggen op een (prive) forum van een race sim (iRacing.com). Het idee van de app is in principe heel simpel: mensen loggen in met hun username/password, daarmee doe ik een HTTP request naar de Login pagina van het forum, en ik onthou de cookies die terug komen. Daarna doe ik voor elke pagina van het forum die de gebruiker opvraagt weer een simpele HTTP request waarbij ik de cookies weer mee stuur zodat de gebruiker ingelogd is.
Dit werkt al tijden lang voor de meeste gebruikers maar eigenlijk vanaf het begin al ontvang ik klachten van mensen waarbij het maar niet wil werken (of misschien 9/10 keer niet en heel af en toe wel).
Door middel van logging ben ik er achter gekomen dat deze mensen doorgestuurd worden naar een pagina wat in principe zegt dat de gebruiker Javascript moet inschakelen. Dit komt er dan in mijn logging als pagina die de gebruiker terug krijgt:
Ik vind dit een vreemde melding, het gaat helemaal niet om een browser maar om een simpele HTTP request met behulp van AsyncHttpClient of DefaultHttpClient (meer later). Waarmee bepaald de website dat er geen Javascript draait? Ik neem aan dat dit met de cookies bepaald wordt, en blijkbaar komen die niet goed mee..?
Het vreemde is nou dat dit op Wifi wel vaak werkt, en mensen op 3G / mobiele connecties vaak problemen hebben. Dit is ook niet altijd waar, er komen ook meldingen binnen waar het op wifi mis gaat, dus dit kan toeval zijn.
Nog vreemder is het dat het voor de meeste gebruikers gewoon werkt, en een handjevol mensen blijven maar problemen hebben. Ook heb ik gebruikers die me wilden helpen met wat meer testjes die na een week of wat van constant problemen ineens geen problemen meer hebben en waar alles nu alweer maanden zonder problemen werkt, zonder ook maar iets te veranderen.
Ik snap er niks meer van... Wat zou hier mis kunnen gaan? Zou het met proxies te maken kunnen hebben ofzo, misschien doen mobiele providers iets vaags met de connectie van sommige mensen?
Dit is in de basis van de code die ik gebruik, er zijn twee versies, ik begon met de DefaultHttpClient (ook geprobeerd de AndroidHttpClient te gebruiken wat in principe dezelfde code is), en toen ik daar niets kon vinden heb ik alles herschreven om gebruik te maken van de AsyncHttpClient. Daar lijkt het beter mee te gaan maar er zijn nog steeds problemen.
DefaultHttpClient:
AsyncHttpClient:
Deze werkt async maar dat had ik zelf al ingebouwd op mijn eigen manier dus ik heb hem weer 'synced' gemaakt op misschien een beetje vreemde manier met CountDownLatch.await, maar dat zal niet het probleem zijn.
Om de code maar even snel samen te vatten, in beide gevallen maak ik eigenlijk een nieuwe Http Client aan, die geef ik een CookieStore mee en daarmee ga ik een GET of POST request doen. Die cookiestore zou dan 'automatisch' gevuld moeten worden en wordt herbruikt voor elke volgende request. De eerste request is dus een request naar de Login pagina, en als de credentials goed zijn komen er een set cookies mee welke de gebruiker authenticeren bij latere requests.
Ik weet het, flinke bak code, maar ik weet niet meer waar ik het moet zoeken. Aangezien alles in mijn eigen testjes en op mijn eigen mobiel prima werkt ben ik een beetje clueless...
Ik verwacht eigenlijk niet dat er iets echt fout is in de code, anders zou het niet werken voor het grootste deel van de gebruikers, maar misschien is er een kleinigheidje wat ik niet zie of niet vanaf weet?
Misschien dat jullie kunnen mee denken om me op de goeie richting te brengen want ik zit nu gewoon echt 100% vast
Bedankt!
Dit werkt al tijden lang voor de meeste gebruikers maar eigenlijk vanaf het begin al ontvang ik klachten van mensen waarbij het maar niet wil werken (of misschien 9/10 keer niet en heel af en toe wel).
Door middel van logging ben ik er achter gekomen dat deze mensen doorgestuurd worden naar een pagina wat in principe zegt dat de gebruiker Javascript moet inschakelen. Dit komt er dan in mijn logging als pagina die de gebruiker terug krijgt:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta name="GENERATOR" content="IBM Software Development Platform"> <meta http-equiv="content-style-type" content="text/css"> <script src="/jforum/templates/iracing/js/jquery.js?ver=1.004"></script> <script src="/jforum/templates/iracing/js/iracing_script.js?ver=1.004"></script> <link rel="stylesheet" href="/jforum/templates/iracing/styles/login.css?ver=1.004" /> <title>Log in | iRacing.com™ Motorsport Simulations</title> </head> <body onLoad = "setInterval('checkField()',50);"> <div id="wrapper"> <div id="feedback"> <div class="warning" id="feedbackTop"></div> <div class="warningTile" id="feedbackMiddle"> <div id="feedbackMessage"> <noscript> <style type="text/css"> /* Initialize noscript styling */ #feedback, #feedbackMessage {display: inline;} #feedbackTop, #feedbackBottom {height: 20px;} #feedbackMessage {height: auto;} </style> <p>JavaScript not enabled. You must enable JavaScript to use iRacing.com™. When you have enabled JavaScript, reload the page to continue checking Internet Browser Requirements.</p> <ul> <li>To enable JavaScript in <strong>FireFox</strong>, go to Tools ⇒ Options ⇒ Content and check the box, "Enable JavaScript".</li> <li>To enable JavaScript in <strong>IE, go to Tools ⇒ Internet Options. Click on the "Security" tab. Click on "Custom level". Scroll down to "Scripting". Check "Enable" on the "Active scripting" setting.</strong></li> <li>To enable JavaScript in <strong>Safari, go to Edit ⇒ Preferences. Click on the "Security" tab. Check "Enable JavaScript".</strong></li> <li>To enable JavaScript in <strong>Chrome, click the wrench icon ⇒ Options. Click on the "Content Settings" button ⇒ JavaScript. Under JavaScript Settings, click "Allow all sites to run JavaScript".</strong></li> </ul> </noscript> </div> </div> <div class="warning" id="feedbackBottom"></div> </div> <div id="content"> <div id="service"> <img src="/jforum/templates/iracing/images/login/email.gif" alt="email" width="29" height="12" /><span><a href="mailto:support@iracing.com">support@iracing.com</a></span> <img src="/jforum/templates/iracing/images/login/faqs.gif" alt="faqs" width="29" height="12" /><span><a href="javascript:launch_FAQ()">FAQs </a></span> </div> <h1>Sign In</h1> <form method="post" name="LOGIN" action="/jforum/Login" > <input class="username" name="username" type="text"/> <input class="password" name="password" type="password" onkeypress="return submitenter(this,event)"/> <input class="hidden" type="hidden" name="utcoffset" value="" /> <input class="hidden" type="hidden" name="todaysdate" value="" /> <input id="checkbox" name="AUTOLOGIN" type="checkbox" onclick="autoLoginWarning()" ><span> Enable Auto Login for this Computer</span> <input id="submit" type="image" src="/jforum/templates/iracing/images/login/submit.gif" value="" onclick="submitLoginForm()" onmouseover="javascript:this.src='/jforum/templates/iracing/images/login/submitHover.gif';" onmouseout="javascript:this.src='/jforum/templates/iracing/images/login/submit.gif';" onmousedown="javascript:this.src='/jforum/templates/iracing/images/login/submitActive.gif';" /> </form> <script type="text/javascript"> $(document).ready(function() { document.LOGIN.username.focus(); var offset = new Date().getTimezoneOffset(); document.LOGIN.utcoffset.value = offset; }); </script> <span><a href="/membersite/recoverpassword.jsp"">Recover Password</a> | <a href="/membersite/SubscriptionChoices.do">Sign Up</a></span> </div> <div id="copyright"> Copyright© <script>document.write(new Date().getFullYear());</script> iRacing.com™ Motorsport Simulations, LLC. All Rights Reserved<br /> <a href="javascript:openTermsWin('/membersite')">Terms of Use and End User License Agreement</a> | <a href="javascript:openPrivacyWin('/membersite')" >Privacy Policy</a> </div> <script type="text/javascript"> var contextpath="/jforum"; var imageserver=""; </script> </div> <script type="text/javascript"> var url = document.location.href; if(url.indexOf("http:")==0){ url = "https"+url.substring(4,url.length); document.location.href = url; } </script> <script type="text/javascript"> function submitenter(myfield,e){ var keycode; if (window.event) keycode = window.event.keyCode; else if (e) keycode = e.which; else return true; if (keycode == 13){ myfield.form.submit(); return false; }else return true; } </script> </body> </html> |
Ik vind dit een vreemde melding, het gaat helemaal niet om een browser maar om een simpele HTTP request met behulp van AsyncHttpClient of DefaultHttpClient (meer later). Waarmee bepaald de website dat er geen Javascript draait? Ik neem aan dat dit met de cookies bepaald wordt, en blijkbaar komen die niet goed mee..?
Het vreemde is nou dat dit op Wifi wel vaak werkt, en mensen op 3G / mobiele connecties vaak problemen hebben. Dit is ook niet altijd waar, er komen ook meldingen binnen waar het op wifi mis gaat, dus dit kan toeval zijn.
Nog vreemder is het dat het voor de meeste gebruikers gewoon werkt, en een handjevol mensen blijven maar problemen hebben. Ook heb ik gebruikers die me wilden helpen met wat meer testjes die na een week of wat van constant problemen ineens geen problemen meer hebben en waar alles nu alweer maanden zonder problemen werkt, zonder ook maar iets te veranderen.
Ik snap er niks meer van... Wat zou hier mis kunnen gaan? Zou het met proxies te maken kunnen hebben ofzo, misschien doen mobiele providers iets vaags met de connectie van sommige mensen?
Dit is in de basis van de code die ik gebruik, er zijn twee versies, ik begon met de DefaultHttpClient (ook geprobeerd de AndroidHttpClient te gebruiken wat in principe dezelfde code is), en toen ik daar niets kon vinden heb ik alles herschreven om gebruik te maken van de AsyncHttpClient. Daar lijkt het beter mee te gaan maar er zijn nog steeds problemen.
DefaultHttpClient:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| public final static String USER_AGENT = "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 3.5.21022)"; public final static String ACCEPT = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/x-shockwave-flash, */*"; private static BasicCookieStore cookieStore; public static BasicCookieStore getCookieStore() { if (cookieStore == null) cookieStore = new BasicCookieStore(); return cookieStore; } public String sendRequest(String url, Params param, int method) { try { DefaultHttpClient httpClient = new DefaultHttpClient(); // Define parameters HttpParams httpParams = httpClient.getParams(); HttpConnectionParams.setConnectionTimeout(httpParams, TIMEOUT); HttpConnectionParams.setSoTimeout(httpParams, TIMEOUT); HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); HttpClientParams.setRedirecting(httpParams, true); // Create HTTP request object (get/post) HttpRequestBase http; HttpContext localContext = new BasicHttpContext(); // Choose between GET / POST if (method == POST) { // Create HTTP POST and set parameters http = new HttpPost(url); if (param != null) { JSONObject json = param.toJson(); HttpEntity bodyEntity = new StringEntity(json.toString(), "utf8"); ((HttpPost)http).setEntity(bodyEntity); } http.addHeader("Accept", ACCEPT); http.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); } else // GET { if (param != null) { // Append parameters to URL and create HTTP GET url = param.appendToUrl(url); } http = new HttpGet(url); } http.addHeader("Accept", ACCEPT); // Attach cookiestore localContext.setAttribute(ClientContext.COOKIE_STORE, getCookieStore()); // Get a response HttpResponse response; try { response = httpClient.execute(http, localContext); } catch (ConnectTimeoutException ex) { throw new TimeoutException(); } HttpEntity entity = response.getEntity(); String result = null; if (entity != null) { InputStream instream = entity.getContent(); BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) sb.append(line + "\n"); result = sb.toString(); instream.close(); } http.abort(); //httpClient.close(); return result; } catch (Exception ex) { Log.e(Constants.TAG, "Error during web request:\n" + ex.toString()); return null; } } |
AsyncHttpClient:
Deze werkt async maar dat had ik zelf al ingebouwd op mijn eigen manier dus ik heb hem weer 'synced' gemaakt op misschien een beetje vreemde manier met CountDownLatch.await, maar dat zal niet het probleem zijn.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| public static AsyncHttpClient getClient() { AsyncHttpClient client = new AsyncHttpClient(); client.getHttpClient().getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1); return client; } private String sendRequest(String url, Params param, int method) throws Exception { AsyncHttpClient client = getClient(); // Set cookiestore client.setCookieStore(getCookieStore()); client.setTimeout(TIMEOUT); client.setUserAgent(USER_AGENT); AwaitResponseHandler handler = new AwaitResponseHandler(); boolean completed; if (method == NetworkMethod.GET) { RequestParams p = new RequestParams(); if (param != null) p = param.toRequestParams(); client.get(url, p, handler); completed = handler.latch.await(TIMEOUT, TimeUnit.MILLISECONDS); } else { HttpEntity entity = null; if (param != null) entity = new StringEntity(param.toJson().toString(), "utf-8"); client.post(context, url, entity, "application/json", handler); completed = handler.latch.await(TIMEOUT, TimeUnit.MILLISECONDS); } if (completed) { return handler.result; } else { throw new TimeoutException(); } } |
Om de code maar even snel samen te vatten, in beide gevallen maak ik eigenlijk een nieuwe Http Client aan, die geef ik een CookieStore mee en daarmee ga ik een GET of POST request doen. Die cookiestore zou dan 'automatisch' gevuld moeten worden en wordt herbruikt voor elke volgende request. De eerste request is dus een request naar de Login pagina, en als de credentials goed zijn komen er een set cookies mee welke de gebruiker authenticeren bij latere requests.
Ik weet het, flinke bak code, maar ik weet niet meer waar ik het moet zoeken. Aangezien alles in mijn eigen testjes en op mijn eigen mobiel prima werkt ben ik een beetje clueless...
Ik verwacht eigenlijk niet dat er iets echt fout is in de code, anders zou het niet werken voor het grootste deel van de gebruikers, maar misschien is er een kleinigheidje wat ik niet zie of niet vanaf weet?
Misschien dat jullie kunnen mee denken om me op de goeie richting te brengen want ik zit nu gewoon echt 100% vast
Bedankt!