Flutter http get api failed, may be for wrong header style
Fundamentally, this comes down to HTTP header names not being case sensitive, and the API server not respecting this.
The header at issue is AuthToken
; if sent through verbatim, the server will accept it but if not, the server will reject it. The Dart http
package sends through the header in lower case (authtoken
) whereas Swift sends through the header maintaining the case (though noting that the names are case insensitive).
Compare:
curl \
--header 'AuthToken: <redacted>' \
--silent \
--verbose \
http://api.orca.faqdev.com.au/api/account/Dashboard > /dev/null
* Trying 52.63.81.235...
* TCP_NODELAY set
* Connected to api.orca.faqdev.com.au (52.63.81.235) port 80 (#0)
> GET /api/account/Dashboard HTTP/1.1
> Host: api.orca.faqdev.com.au
> User-Agent: curl/7.64.1
> Accept: */*
> AuthToken: <redacted>
>
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Server: Microsoft-IIS/10.0
< X-Powered-By: ASP.NET
< Date: Tue, 29 Jun 2021 06:53:33 GMT
< Content-Length: 1697
<
{ [1697 bytes data]
* Connection #0 to host api.orca.faqdev.com.au left intact
* Closing connection 0
vs:
curl \
--header 'authtoken: <redacted>' \
--silent \
--verbose \
http://api.orca.faqdev.com.au/api/account/Dashboard > /dev/null
* Trying 52.63.81.235...
* TCP_NODELAY set
* Connected to api.orca.faqdev.com.au (52.63.81.235) port 80 (#0)
> GET /api/account/Dashboard HTTP/1.1
> Host: api.orca.faqdev.com.au
> User-Agent: curl/7.64.1
> Accept: */*
> authtoken: <redacted>
>
< HTTP/1.1 401 Unauthorized
< Transfer-Encoding: chunked
< Server: Microsoft-IIS/10.0
< X-Powered-By: ASP.NET
< Date: Tue, 29 Jun 2021 06:54:42 GMT
<
{ [5 bytes data]
* Connection #0 to host api.orca.faqdev.com.au left intact
* Closing connection 0
The best solution is to configure the API server to treat all headers as case insensitive (as per the spec), then it will work for all clients.
If you absolutely positively can't do that, there is an option to use the HttpClient
provided by dart:io
, and in that scenario your implementation would end up something like:
import 'dart:convert';
import 'dart:io';
...
final client = HttpClient();
final request = await client
.getUrl(Uri.parse('http://api.orca.faqdev.com.au/api/account/Dashboard'));
request.headers.set('AuthToken', '<redacted>', preserveHeaderCase: true);
final response = await request.close();
final chunks = await response.transform(utf8.decoder).toList();
final body = chunks.join('');
client.close();
// handle the response
print(body);
Note the use of preserveHeaderCase
on the HttpHeaders.set
method
Jamshed Alam
I am an iOS developer with 7+ years of professional experience. I enjoy developing the latest work on many projects and always heartily try to learn about new technology. I am working with Xcode, Objective-C, Swift, and Cocos2d. I am interested in best practices that are being adopted by the iOS community and implementing them into my work. I have developed productivity, lifestyle, utility-related apps, and many more. Professional Expertise: Languages: Objective-C, Swift. iOS Frameworks/API: iOS 6.00-iOS 15.0, UIKit, SwiftUI, AVFoundation, CoreLocation, CoreGraphics, CoreAnimation, MapKit, RESTKit, AFNetworking, MKStoreKit, GCD, Thread, Custom UI Elements, Auto Layout, CocoaPods, SQLite, Core Data, iAD, GoogleMobileAds, SDWebImage, File System, Contact, CloudKit, Push/Local Notification, In-App Purchase and everything related to app store submission. IDE: Xcode. Source Control: Git. Find me on LinkedIn , Facebook , Skype : codetolive99 App Links : SelfieYo Chat Burn 2 Learn , Fitness app HungryNaki - Food Delivery App Email me at [email protected]
Updated on December 30, 2022Comments
-
Jamshed Alam over 1 year
Just started implementing API(get, post mostly) in Flutter. I was getting the post API response well but for GET API, I am getting 401. The code is given below:
import 'package:http/http.dart' as http; String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJZCI6IjgiLCJVc2VyRGV2aWNlSWQiOiI0NTVENDY3Rjc4MjI0QjlDOERFN0JDMjFFNjREQjVEQyIsIkZ1bGxOYW1lIjoiQW5keSBNZW1iZXIiLCJQaG9uZSI6IjA0MjM5OTkzMzMiLCJlbWFpbCI6Im1rYWJpckBmYXFpLmNvbS5hdSIsInN1YiI6IjA0MjM5OTkzMzMiLCJqdGkiOiJkZGY3NDM4OC03YzE4LTQyZjktODdkMC0yMGQzY2NjNDE2ZGIiLCJuYmYiOjE2MjQ5NDIxNzAsImV4cCI6MTYyNDk2Mzc3MCwiaWF0IjoxNjI0OTQyMTcwfQ.I9pR2HZbKlOwl_9Z5O5AE8kZh0o5SdTOxsvTsY28SUk"; var headers = { 'AuthToken': token, 'accept': 'application/json', }; final response = await http.get('http://api.orca.faqdev.com.au/api/account/Dashboard' , headers: headers);
Two things regarding the API :
- It is working from the postman
- It is working from iOS Swift code.
Anyone can guess what happens here in Flutter? BTW, I am new in Flutter.
-
John Joe almost 3 yearsis headers param and value you used are same with
Postman
? -
p2kr almost 3 yearsAre you sure the website is up or API working? maybe problem on site side, or check your API token again.
-
Jamshed Alam almost 3 yearsthe same token is using postamn!
-
msbit almost 3 yearsThere will almost certainly be a discrepancy between the headers Postman/Swift/Flutter implementations are using, perhaps because each is making different assumptions about
Content-Type
etc. Take a good look at the full set of headers each is sending, and compare them. -
msbit almost 3 yearsAlso confusing things, perhaps, is that this token is now expired (ie the server responds with HTTP status 401 and
Token-Expired: true
header). It would be worth checking again with a refreshed token. -
Jamshed Alam almost 3 yearsToken updated, you can check now on postman.
-
msbit almost 3 yearsOkay, so running that code, (after fixing the issue with
get
needingUri
, notString
), I can see that Dart sends the following headers:user-agent: Dart/2.13 (dart:io), accept: application/json, accept-encoding: gzip, authtoken: <token>, content-length: 0
If the API needs more than that, you'll need to add them in as part of theheaders
argument forget
. -
Jamshed Alam almost 3 yearsI set Uri also, i got the same. I've updated the token just now. Could you please hit it once? I think the reason is tricky/silly. @msbit
-
msbit almost 3 yearsHow about you put the headers you are putting into Postman, and the Swift implementation, into the question, to see if there are any discrepancies.
-
Jamshed Alam almost 3 yearsThought the same, but was not known about the preserveHeaderCase. Awesome job dear @msbit.
-
msbit almost 3 yearsHappy to help, @JamshedAlam. I would like to stress again, that if you are developing the API also, set it up such that the case of headers doesn't matter, it will save you possible heartache in future too :)