級別:★☆☆☆☆
標籤:「Flutter web」「Dart Server」「blocked by CORS Policy」「跨域」
做者: WYW
審校: QiShare團隊
php
前言 筆者最近了解了Flutter web相關的內容,本文會分享建立Flutter web項目、Flutter web項目預覽,Flutter web項目和Flutter mobile(Flutter Android/iOS)項目的差異、搭建簡易Dart服務器(解決跨域問題)、上線Flutter web項目相關內容。html
flutter channel beta
nginx
flutter upgrade
git
Flutter有以下4個channel:github
flutter channel
Flutter channels:
beta
* dev
master
stable
複製代碼
Flutter 官方建議使用 stable 的channel。web
master 是當前最新的channel;chrome
dev 是當前最新的充分測試後的channel;api
beta是每月Flutter官方調整選出來的最好的dev的channel,並提高爲beta channel;跨域
stable是Flutter 認爲是當前最穩定的channel。瀏覽器
穩定性而言:master < dev < beta < stable 。更多內容可查看:Flutter build release channels
flutter config --enable-web
若是想在當前已有項目Flutter mobile項目的基礎上,添加Flutter web支持,可 cd 到 Flutter mobile 項目目錄下,添加Flutter web支持。
若是以前沒有建立過Flutter 項目,新建一個Flutter web項目可使用以下命令。
flutter create 項目名(小寫)
如:flutter create qi_flutter_web_demo
若是以前建立過Flutter 項目,想現有項目生成web文件夾及index.html等文件可以使用以下命令。
flutter create .
運行項目命令:flutter run -d chrome
運行失敗報錯以下:
wangyongwangdeiMac:qi_flutter_page wangyongwang$ flutter run -d chrome
Flutter assets will be downloaded from storage.flutter-io.cn. Make sure you trust
this source!
Downloading Web SDK... 1.1s
Launching lib/main.dart on Chrome in debug mode...
Error compiling dartdevc module:qi_flutter_page|lib/main_web_entrypoint.ddc.js
packages/qi_flutter_page/main_web_entrypoint.dart:9:18: Error: Too few positional arguments:
1 required, 0 given.
entrypoint.main();
^ 複製代碼
AssetNotFoundException: qi_flutter_page|lib/main_web_entrypoint.ddc.js
Failed after 23.3s
Building application for the web... 33.5s
Failed to build application for the Web.
起初,筆者猜想緣由是這個網址https://storage.flutter-io.cn.訪問不可達;不過試過運行新建立的Flutter web項目,發現新建的Flutter web項目能夠正常運行,能夠排除問題不在於網址https://storage.flutter-io.cn.訪問不可達。
繼續看這段報錯,能夠發現Flutter web 項目的main 方法中不能有參數。
packages/qi_flutter_page/main_web_entrypoint.dart:9:18: Error: Too few positional arguments: 1 required, 0 given. entrypoint.main(); ^
AssetNotFoundException: qi_flutter_page|lib/main_web_entrypoint.ddc.js
Failed after 22.9s
運行Flutter web 項目的時候,main方法中不能有參數。
void main(List<String> args) {
}
// 刪除main方法名中的參數後,能夠正常運行。
void main() {
}
複製代碼
筆者以以前寫的項目qi_flutter_page爲例:運行起來的效果以下:
上週和同事CH聊天學到的內容:Flutter web項目顯示的網頁的特色:
顯示網頁源代碼的時候,能夠網頁發現顯示的內容是html的body 中嵌套的main.dart.js。
運行Flutter web項目 默認會在Chrome瀏覽器中顯示,不過在本機的Safari 瀏覽器中及模擬器中的瀏覽器中輸入相應的網址,也能夠顯示相應的視圖。
筆者在把現有Flutter mobile項目,直接支持Flutter web 的過程當中遇到了網絡請求報異常的問題,另外簡單測試了2個三方庫的在Flutter web項目中的體現。
try {
HttpClient client = HttpClient();
} catch (e) {
print('捕獲異常:$e');
}
複製代碼
捕獲異常:NoSuchMethodError: invalid member on null: 'indexOf'
Flutter web項目的網絡請求可使用html.httpRequest。
import 'dart:html' as html;
html.HttpRequest.request(url).then((responseValue) {
});
複製代碼
筆者這裏舉2個本身使用過三方庫,shared_preferences、url_launcher。
下列代碼對於Flutter web 項目中仍然支持打開加載url的窗口。
String soUrl = 'https://www.so.com';
if (await canLaunch(soUrl)) {
await launch(soUrl);
}
複製代碼
由以下代碼及相應結果可知,shared_preferences 也支持 Flutter Web 項目。
void _incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
await prefs.setInt('counter', counter);
}
複製代碼
ListTile2 Pressed 1 times. ListTile2 Pressed 2 times. ListTile2 Pressed 3 times. ListTile2 Pressed 4 times. ListTile2 Pressed 5 times.
三方庫通常會註明支持的平臺(Android、iOS或Web)。 url_launcher 5.4.1支持 Flutter web 項目。 shared_preferences 支持 Flutter web 項目。 sqflite本身註明了支持Android和iOS,是否支持Flutter web沒有作說明。
以下圖所示:
使用以下代碼,能夠本地啓動一個Dart服務。
main() async {
var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 9988);
await for (var request in server) {
request.response
..headers.contentType = ContentType('text', 'plain', charset: 'utf-8')
..write('Hello Dart! 你好Dart')
..close();
}
}
複製代碼
瀏覽器中直接請求http://127.0.0.1:9988 示意圖以下:
筆者在Flutter web項目中請求,http://127.0.0.1:9988的時候,遇到了跨域問題,下邊分享下相關問題及處理方式。
跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。當一個資源從與該資源自己所在的服務器不一樣的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。
好比,站點 domain-a.com 的某 HTML 頁面經過 的 src 請求 domain-b.com/image.jpg。網…
出於安全緣由,瀏覽器限制從腳本內發起的跨源HTTP請求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 這意味着使用這些API的Web應用程序只能從加載應用程序的同一個域請求HTTP資源,除非響應報文包含了正確CORS響應頭。 引自HTTP訪問控制(CORS)
舉2個例子好比咱們自身當前域名爲abc.com, 訪問def.com 會出現跨域的問題。 好比咱們自身當前域名爲abc.com端口號爲1234(abc.com:1234),那麼訪問abc.com:5678也會出現跨域問題。
筆者使用Flutter web項目請求服務端資源的時候遇到了跨域問題。
http://localhost:55355/#/ 中的內容訪問http://127.0.0.1:9988
Flutter web項目跨域現象圖現象圖以下:
出現當前跨域問題的緣由是端口號不一樣,訪問Flutter web項目的url 和 請求服務端資源的url的 端口號
不一樣。
設置跨域的url 有2種設置方式:
..headers.add('Access-Control-Allow-Origin', '*')
複製代碼
注意:若是在本地測試使用,可使用第二種方式,直接了當。可是通常線上的話最好使用第一種方式設置是否能夠跨域請求。由於設置是否能夠跨域,算是服務器在響應瀏覽器請求數據時的一種保護策略。
其中重點是在響應頭中添加能夠跨域的請求域。
..headers.add('Access-Control-Allow-Origin', 'http://localhost:55355')
如'Access-Control-Allow-Origin'能夠指定特定的url,使url可以跨域請求。
若有須要指定容許多個url進行跨域請求。能夠根據請求的origin的值,判斷是否要作跨域響應頭的處理。
如:以下代碼設置了當請求的origin 爲http://localhost:63062
或 http://localhost:55355
的時候,會添加跨域處理的響應頭。
main() async {
var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 9988);
var server = await HttpServer.bind(InternetAddress.loopbackIPv4, 9988);
await for (var request in server) {
var accessControlAllowOrigin = [
'http://localhost:63062',
'http://localhost:55355'
];
if (request.headers['origin'] != null) {
for (String tempAllowOrigin in accessControlAllowOrigin) {
if (request.headers['origin'].first.contains(tempAllowOrigin)) {
request.response
..headers
.add('Access-Control-Allow-Origin', request.headers['origin'])
// ..headers.add('Access-Control-Allow-Origin', '*')
..headers.contentType =
ContentType('text', 'plain', charset: 'utf-8')
..write('Hello Dart! 你好Dart 跨域')
..close();
}
}
} else {
request.response
..headers.contentType = ContentType('text', 'plain', charset: 'utf-8')
..write('Hello Dart! 你好Dart 不須要跨域')
..close();
}
}
}
複製代碼
筆者在上邊說明了處理運行Flutter web項目的時候,處理本地服務端接口和Flutter web項目運行網址出現跨域問題的處理方式。(其實對於編譯後的Flutter web項目的產物直接放到本身的服務端項目的的靜態文件目錄下的時候,不會出現上述問題) 有時候咱們的請求內容可能就須要跨域去請求數據,並且對方若是也不便添加相應的跨域響應頭。此時,可以使用Nginx 作反向代理來處理跨域問題。
server {
listen 9080;
server_name localhost;
location ~ /columns/Qtest {
proxy_pass https://testerhome.com;
}
}
複製代碼
經上述處理,能夠在本地的127.0.0.1:9080/columns/Qtest請求到 Qtest測試之道的 testerhome.com/columns/Qte… 相應數據。
Nginx 配置反向代理及rewrite訪問路徑可實現訪問遠端文件不跨域。
location / {
proxy_pass https://weekly.75team.com;
}
location ~ /api/qiwuzhoukanWeb {
rewrite /api/qiwuzhoukanWeb /;
proxy_pass https://weekly.75team.com;
}
複製代碼
經上述處理,能夠在本地的127.0.0.1:9080/api/qiwuzhoukanWeb請求到 奇舞週刊的 weekly.75team.com 相應數據。
flutter build web
會在項目的build 目錄中生成相應的資源文件及html 和js文件,把相關文件放置到服務端靜態文件目錄下便可。實現上線Flutter Web項目。
瞭解更多iOS及相關新技術,請關注咱們的公衆號:
小編微信:可加並拉入《QiShare技術交流羣》。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
用AdHoc來測試iOS線上推送 Swift 5.1 (9) - 結構體和類
Swift 實現一個兼容iOS、tvOS、OSX的抽象層
iOS Password AutoFill
iOS 給UILabel添加點擊事件
用SwiftUI給視圖添加動畫
用SwiftUI寫一個簡單頁面
Swift 5.1 (8) - 枚舉類型 iOS App啓動優化(三)—— 本身作一個工具監控App的啓動耗時
iOS App啓動優化(二)—— 使用「Time Profiler」工具監控App的啓動耗時
iOS App啓動優化(一)—— 瞭解App的啓動流程
奇舞週刊