Flutter Web - Some Notes. CORS (Cross-Origin Resource Sharing) - by Vinay Shankri - Flutter Community - Dec, 2020 - Medium
Flutter Web - Some Notes. CORS (Cross-Origin Resource Sharing) - by Vinay Shankri - Flutter Community - Dec, 2020 - Medium
e Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
tl;dr
I recently started working on a new Flutter project primarily for the Web (of course
works on devices as well). I want to share few things that I had to sort out before getting
steady and speeding through web app development such as:
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 1/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
I have custom SSE implementation (Server Sent Events) as “dio” did not cut it. Please refer
Server Sent Events(SSE) with Flutter for more information.
Hot Reloading
Currently, hot reloading is not supported in Chrome. You have to press “r” or “R” in VS
code terminal every time you want your changes to reflect in your browser. Hopefully,
sometime soon hot reloading in Chrome will be the same as the Android emulator or iOS
simulator.
To circumvent this, I run my app both on Chrome and iOS simulator for faster
development. This also helps me instantly test responsive and reactive screens.
Step-wise debugging
Unfortunately at this point, we cannot step-wise debug our code (In VS Code) when
running on Chrome. For now, I debug in the iOS simulator or Android emulator. Even
though it is not terribly bad, I hope we get this feature at the earliest.
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 2/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
The above command opens a new copy of the Chrome browser and assigns a new port at
runtime, for example, http://localhost:62731/#. Now all Flutter web pages are served
from port “62731” and my REST endpoint is running on a different port (Java-based
microservice) example: http://localhost:8080/myproject/myendpoint.
Now CORS kicks in on the browser because of 2 different ports. The browser needs
permission to access REST endpoints running on port 8080.
Note: CORS is independent of the authentication and authorization mechanism of your app
flutter run -d chrome --web-port=9090: With this command, we can specify the port.
Now we can set up our own proxy server to overcome CORS. This needs extra setup +
All logs and exceptions appear in the Chrome browser’s console and not on VS code
terminal.
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 3/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
Note: CORS preflight request is an HTTP OPTIONS call made by the browser asking for
permission. We need to respond with the below headers and a response status of 202 when
the HTTP method == OPTIONS. I am handling this in Servlet Filter of my Java-based
microservice.
1 if("y".equalsIgnoreCase(System.getProperty("dev"))){
2 response.addHeader("Access-Control-Allow-Origin", "*");
3 response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELE
4 response.addHeader("Access-Control-Allow-Headers", "custId, appId, Origin, Conten
5 response.addHeader("Access-Control-Expose-Headers", "Authorization, authenticated
6 response.addHeader("Access-Control-Max-Age", "1728000");
7 response.addHeader("Access-Control-Allow-Credentials", "true");
8 }
line #2: “*” is for all domains and ports. However, you can whitelist IPs as well.
line #3: We need to whitelist all headers that are part of the request. This is a must for
CORS if you plan to send app-specific custom headers. In the above example, “custId” &
“appId” are custom headers.
I have tested (dio or default) this and it works fine on devices and the web.
I will try to keep it simple and not include my app-specific nuances. I have 3 classes:
Application Constants, Simple Logger, and an abstract class (AbstractHttp.dart) that all
service classes (all classes responsible for making REST calls) extend.
Application Constants
line#10: Production URL for iOS & Android devices (Web app uses relative path)
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 4/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
line #14 through #17: Constants specific to DEV mode as used in AbstractHttp.data
1 ///Application Constants
2 class AppConstants {
3 ///DEV OR PROD MODE
4 static const bool isProd = bool.fromEnvironment('dart.vm.product');
5
6 ///DEV OR PROD MODE
7 static const bool isDev = !bool.fromEnvironment('dart.vm.product');
8
9 ///this is base URI for non-web browser (for browser it is relative path)
10 static final String prodBaseUri = 'https://myprodurl/';
11
12 ///*** START: DEV related */
13 ///base URI when on isDev == true
14 static final bool useDevHeaders = true;
15 static final String devBaseUri = 'http://localhost:8080';
16 static final String custId = 'XYZ_COMPANY';
17 static final String appId = 'G3GYEP314WM1MZ37';
18
19 ///*** END: DEV related */
20 }
Logger
A simple logging wrapper for the Logger package. In this example, I am just printing log
statements to the console. In my app, it is integrated with SPLUNK
1 import 'package:logging/logging.dart';
2
3 ///simple logger class (singleton) that writes to console
4 ///this can be customized to you app's requirement
5 ///refer this link for more info: https://pub.dev/packages/logger
6 class XLogger {
7 static final XLogger _xLogger = XLogger._internal();
8
9 ///I am just using 'main' for simplicity
10 ///In actual app you can have logger for each module
11 var logger = Logger('main');
12
13 factory XLogger() {
14 return _xLogger;
15 }
16
17 XLogger._internal() {
18 _init();
19 }
20
21 void init() {
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 5/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
21 void _init() {
22 Logger.root.level = Level.ALL;
23 Logger.root.onRecord.listen((record) {
24 if (record.error != null && record.stackTrace != null) {
25 print('${record.level.name}: ${record.loggerName}: ${record.time}: ${record.mess
26 print(
27 'level: ${record.level.name} loggerName: ${record.loggerName} time: ${record
28 } else if (record.error != null) {
29 print('level: ${record.level.name} loggerName: ${record.loggerName} time: ${reco
30 } else {
31 print('level: ${record.level.name} loggerName: ${record.loggerName} time: ${reco
32 }
33 });
34 }
35 }
AbstractHttp
All service classes (classes making REST calls) across modules of my app extend
AbstractHttp. The main idea is to keep things centralized.
line #24: _init() method sets timeouts, adds 2 interceptors (logging and app-specific
interceptor), and prepares base URL (line #4). Logging interceptor is great to see details
of REST calls in VS Code terminal.
line #61: _prepBaseUri() adjusts base URL based on DEV, PROD, Web, and for devices.
This really helps to test seamlessly on local dev and in different environments.
1 import 'package:dio/dio.dart';
2 import 'package:flutter/foundation.dart';
3 import 'package:logging/logging.dart';
4 import 'package:meta/meta.dart';
5 import 'package:universal_html/html.dart' as html;
6
7 ///abstract class that all service classes extend
8 abstract class AbstractHttp {
9 static const String custId = 'CustID';
10 static const String appId = 'appID';
11
12 static Dio _dio;
13
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 6/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
14 String _baseUri;
15
16 @mustCallSuper
17 AbstractHttp() {
18 _init();
19 }
20
21 Dio get dio => _dio;
22
23 ///init common dio options
24 void _init() {
25 if (_dio == null) {
26 _dio = new Dio();
27 _dio.options.connectTimeout = 5000;
28 _dio.options.receiveTimeout = 10000;
29
30 if (_dio.interceptors.length == 0) {
31 _dio.interceptors.add(LogInterceptor(responseBody: false, logPrint: (msg) => XLo
32 _interceptor();
33 }
34 _baseUri = _prepBaseUri();
35 }
36 }
37
38 ///URL = base URI + + specific endpoint
39 String getUrl(String endpointSpecificUri) => _baseUri + endpointSpecificUri;
40
41 ///single custom rest interceptor
42 ///keeping it simple with basic implementation
43 void _interceptor() {
44 _dio.interceptors.add(InterceptorsWrapper(
45 onRequest: (RequestOptions options) async {
46 ///adding headers in DEV mode based on AppConstants
47 if (AppConstants.isDev && AppConstants.useDevHeaders) {
48 options.headers.addAll({custId: AppConstants.custId, appId: AppConstants.appId
49 }
50 return options;
51 },
52 //just got valid response from server
53 onResponse: (Response response) async => response,
54
55 ///just received error from server
56 onError: (DioError e) async => e,
57 ));
58 }
59
60 ///base URI
61 String _prepBaseUri() {
62 ///in DEV mode, devBaseUri is common for web and devices
63 if (AppConstants.isDev) {
64 ///dev URL for both web and devices
65 return AppConstants.devBaseUri;
66 } l if ( C i d k b) {
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 7/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
66 } else if (AppConstants.isProd && kIsWeb) {
67 ///relative URL for web in production
68 return html.window.location.toString();
69 } else {
70 ///absolute URL for iOS and android devices
71 return AppConstants.prodBaseUri;
72 }
73 }
74 }
CONCLUSION
It is a breeze to start a Flutter app for iOS and Android. Flutter Web is still in beta and
has some catching up to do. Based on the speed of Flutter’s evolution, I am hoping
Flutter Web to be out of beta very soon. I just wanted to share a few things that helped
me on my Flutter Web project. I plan to take it to production early next year.
Thank you.
Vinay
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 8/9
13/1/2021 Flutter Web: Some Notes. CORS (cross-origin resource sharing)… | by Vinay Shankri | Flutter Community | Dec, 2020 | Medium
https://medium.com/flutter-community/flutter-web-for-an-enterprise-app-a056fb4e26d1 9/9