-
Notifications
You must be signed in to change notification settings - Fork 26.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Override HttpClient globally #19588
Comments
You can override all HTTP clients globally using For example: class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext securityContext) {
return new HttpClient()
.. badCertificateCallback = ...;
}
void main() {
HttpOverrides.global = new MyHttpOverrides();
runApp(...)
} We do this in flutter test as well with some mocks:
|
Dup of #13792 ? |
@jonahwilliams thanks! class MyHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext securityContext){
return new HttpClient(context: securityContext)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}
void main() {
HttpOverrides.global = new MyHttpOverrides();
runApp(new MyApp());
}
//the call is
Future<String> getContent() async{
var response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
return response.body;
}``` |
@pepie can you post the full stack trace? |
@jonahwilliams Thanks for your help with this. I really appreciate it. Here's the sample code: I can see that createHttpClient() is called many times, which is likely what is overflowing the stack. import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
//import 'package:secure/utils/ApiHelper.dart';
class AppHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext securityContext){
return new HttpClient()
..badCertificateCallback =(X509Certificate cert, String host, int port) => true;
}
}
Future<String> getContent() async{
var url = 'https://jsonplaceholder.typicode.com/posts/1';
try{
var response = await http.get(url);
return response.body;
}catch(err, stacktrace){
print(err);
debugPrint(stacktrace.toString());
return err.toString();
}
}
void main() {
HttpOverrides.global = new AppHttpOverrides();
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'HTTP DEMO'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _data = '[nothing yet]';
void loadData() async{
getContent().then((result){
setState(() {
_data = result;
});
}).catchError((err){
_data = err.toString();
}).whenComplete((){
print('done!');
});
}
@override
Widget build(BuildContext context) {
//ApiHelper rest = new ApiHelper();
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Center(
child: new Column(
children: <Widget>[
new Text('Web Result:',
style: Theme.of(context).textTheme.display1,
),FutureBuilder(
future: getContent(),
//future: rest.getContent(),
builder: (context, snapshot){
if(snapshot.hasData){
return new Text(snapshot.data.toString());
}else if(snapshot.hasError){
print(snapshot.error.toString());
return new Text(snapshot.error.toString());
}
return new Container();
},
),
],
),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
loadData();
},
tooltip: 'Load Data',
child: new Icon(Icons.refresh),
),
);
}
} Logs:
|
Ahh @pepie I made a silly mistake - creating a new HttpClient will call your HttpOverrides which will recurse endlessly. Instead use runZoned like this: void main() {
HttpOverrides.runZoned(() {
runApp(MyApp);
}, createHttpClient: (SecurityContext _) {
return new HttpClient();
});
} |
@jonahwilliams still no luck. A few questions:
class MyHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext securityContext){
return new HttpClient()
..badCertificateCallback =(X509Certificate cert, String host, int port) => true;
}
} Should your code sample (above) use 'MyHttpOverrides' instead of HttpOverrides? void main() {
MyHttpOverrides.runZoned(() {
runApp(MyApp);
}, createHttpClient: (SecurityContext _) {
return new HttpClient();
});
} or, are you saying MyHttpOverrides is no longer needed? 2b) Since HttpOverrides.runZoned() creates a new zone, which is different from the root zone, then I guest the following should also work (w/o having to declared MyHttpOverride): HttpOverrides.runZoned(() {
runApp(new MyApp());
}, createHttpClient: (SecurityContext context) {
return new HttpClient(context: context)
..badCertificateCallback =(X509Certificate cert, String host, int port) => true;
}) But that one failed with 'CERTIFICATE_VERIFY_FAILED'. I've tried the following (with MyHttpOverrides defined as listed above): void main(){
HttpOverrides.runZoned(() {
runApp(new MyApp());
}, createHttpClient: (SecurityContext _context) {
return new HttpClient();
});
} w/ runWithHttpOverrides void main(){
HttpOverrides.**runWithHttpOverrides**((){
runApp(new MyApp());
}, new MyHttpOverrides());
;
} all in one: void main(){
HttpOverrides.runZoned(() {
runApp(new MyApp());
}, createHttpClient: (SecurityContext securityContext) {
HttpClient _client = HttpClient(context: securityContext);
_client.badCertificateCallback =(X509Certificate cert, String host, int port) => true;
return _client;
});
} FYI: I've also uninstalled the app cleared the ide (Android Studio) cache several times, to be sure. |
With the above snippet you should not use HttpOverrides.global or a class that extends HttpOverrides |
@jonahwilliams the runZone option still doesn't work. This seems to be a major bug, actually. void main() async{
HttpOverrides.runZoned(() {
runApp(new App());
}, createHttpClient: (SecurityContext securityContext) {
return new HttpClient(context: securityContext)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
});
} As you mentioned, the fact that HttpClient() is called within createHttpClient is creating an infinite loop. Looking at the code, your first suggestion and the runZoned option had the right intention and should have worked. It seems either createHttpClient(overrides.dart:100) or the HttpClient factory (http.dart:1589) should keep track of the client instance. Or another method to create a client should be exposed. @override
HttpClient createHttpClient(SecurityContext context) {
if (_createHttpClient != null) return _createHttpClient(context);
if (_previous != null) return _previous.createHttpClient(context);
return super.createHttpClient(context);
} http.dart:1589 factory HttpClient({SecurityContext context}) {
HttpOverrides overrides = HttpOverrides.current;
if (overrides == null) {
return new _HttpClient(context);
}
return overrides.createHttpClient(context);
} |
I just noticed @zoechi flagged this as severe. |
You're right that doesn't work either. We never hit this because we always used mocks which reimplemented HttpClient. I also tried to use a client created outside of the runZoned scope, but that crashes: void main() {
// Temporary debugging hook for https://github.com/flutter/flutter/issues/17956
debugInstrumentationEnabled = true;
final HttpClient client = new HttpClient();
HttpOverrides.runZoned(() {
new HttpClient();
runApp(const GalleryApp());
}, createHttpClient: (SecurityContext context) {
return client;
});
} Stack trace:
As long as you don't need network assets and images to work (yikes), you could start by creating a top level http client somewhere while we sort this out. |
@zanderso - is there a proper way to use HttpOverrides, either global or runZoned, such that I can replace the |
If you extend class MyHttpClient implements HttpClient {
HttpClient _realClient;
MyHttpClient(this._realClient);
...
}
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext context) {
return new MyHttpClient(super.createHttpClient(context));
}
}
main() {
HttpOverrides.global = new MyHttpOverrides();
...
} |
Thank you @zanderso! |
@jonahwilliams @zanderso fantastic!! Thank you for the help. super.createHttpClient(context) did the trick! I got it working with the following: class MyHttpOverrides extends HttpOverrides{
@override
HttpClient createHttpClient(SecurityContext context){
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
}
}
void main(){
HttpOverrides.global = new MyHttpOverrides();
runApp(new MyApp());
} Thank you for the help! |
Can this issue be closed then? |
Sounds good |
运行 |
flutter clean not work. |
Thank you very very very much, this helped me! |
It works with web_socket_channel! |
It looks that this is working, but what if we want to add our .crt or .pem file. I couldn't make any https requests with them. Can you advice me how to add one of those files to the app and make the https requests ? I have been struggling with this for a long time. Thanks in advance. |
https://dart-lang.github.io/server/tls-ssl.html#connecting-to-an-https-resource ..setTrustedCertificates(file: 'myTrustedCAs.pem'); https://api.flutter.dev/flutter/dart-io/SecurityContext/setTrustedCertificates.html |
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
Hello,
I'm having trouble making network calls to a development box w/ a self-signed certificate.
Is there a way to override HttpClient globally?
Flutter throws a CERTIFICATE_VERIFY_FAILED, when making calls to a server with self-signed certificate.
This can be bypassed with the badCertificateCallback() like so
This must be done on a case-by-case basis, however, as overriding one client instance does not make it possible to use other features that depends on HttpClient, but does not expose the HttpClient object.
For example,
Suppose I want to
The call to NetworkImage() would fail, because NetworkImage uses a new instance HttpClient:
Is there a better way to do this?
The text was updated successfully, but these errors were encountered: