質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

1回答

9934閲覧

FlutterからAPIアクセスする際に、XMLHttpRequest errorのエラーが出る

ganec

総合スコア1

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2021/07/10 01:44

編集2021/07/10 01:49

前提・実現したいこと

Flutter(Dart)を用いて、外部APIにアクセスして情報を取得するシステムを作っています。
HotPepperのAPIから情報を取得するテストとして、ターミナルに取得した情報を表示するプログラムを実行する際にエラーが発生しました。

参考にしたサイト:https://qiita.com/abouch/items/90107b330bb126a6f742

発生している問題・エラーメッセージ

await http.get(Uri.parse(url)).then((response)...の部分で、以下のエラーが発生した。

Error: XMLHttpRequest error. dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 909:28 get current packages/http/src/browser_client.dart 71:22 <fn> dart-sdk/lib/async/zone.dart 1613:54 runUnary dart-sdk/lib/async/future_impl.dart 155:18 handleValue dart-sdk/lib/async/future_impl.dart 707:44 handleValueCallback dart-sdk/lib/async/future_impl.dart 736:13 _propagateToListeners dart-sdk/lib/async/future_impl.dart 533:7 [_complete] dart-sdk/lib/async/stream_pipe.dart 61:11 _cancelAndValue dart-sdk/lib/async/stream.dart 1219:7 <fn> dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 324:14 _checkAndCall dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 329:39 dcall dart-sdk/lib/html/dart2js/html_dart2js.dart 37307:58 <fn> at Object.createErrorWithStack (http://localhost:55435/dart_sdk.js:5054:12) at Object._rethrow (http://localhost:55435/dart_sdk.js:37670:16) at async._AsyncCallbackEntry.new.callback (http://localhost:55435/dart_sdk.js:37666:13) at Object._microtaskLoop (http://localhost:55435/dart_sdk.js:37526:13) at _startMicrotaskLoop (http://localhost:55435/dart_sdk.js:37532:13) at http://localhost:55435/dart_sdk.js:33303:9

該当のソースコード

dart

1import 'package:flutter/material.dart'; //google提供のUIデザイン 2import 'package:http/http.dart' as http; //httpリクエスト用 3import 'dart:async'; //非同期処理用 4import 'dart:convert'; //httpレスポンスをJSON形式に変換用 5 6void main() { 7 HotPepperClient.fetchHotPepper().then((restaurants) => { 8 restaurants?.forEach((restaurant) => {print(restaurant.name)}) 9 }); 10} 11 12class HotPepper { 13 (略) 14} 15 16class HotPepperClient { 17 static Future<List<HotPepper>?> fetchHotPepper() async { 18 String baseUrl = 19 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key=******************'; 20 String url = baseUrl + "&lat=**.*****&lng=**.*****&format=json"; 21 print(url); 22 await http.get(Uri.parse(url)).then((response) { 23 print(response); 24 if (response.statusCode == 200) { 25 final List<dynamic> jsonArray = json.decode(response.body); 26 return jsonArray.map((json) => HotPepper.fromJson(json)).toList(); 27 } else { 28 throw Exception('Failed to load article'); 29 } 30 }); 31 } 32}

試したこと

  • URLは正しいことを確認しています(ブラウザ直打ちで、json形式で取得できた)
  • エラーについて調査しましたが、サーバー側を改変しなければならないものが多く、クライアント側で解決する方法が見つかりませんでした
  • https://www.fixes.pub/program/452586.html

実行環境

  • Mac Book Pro (intel)
  • VS Code
  • Chrome (Web)

よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

Flutterに関しては未経験なので、回答が誤っている可能性があります。

Flutter Webとしての動作時の問題ということであっているでしょうか?

その場合、XMLHttpRequestとあることからブラウザのセキュリティのためにあるCORSの対応が必要なようにみえます。
ブラウザのアドレスバーに直打ちで通ることからよりCORS絡みの可能性はより高いです。
また、ブラウザ(JavaScript)からのホットペッパAPIの利用でCORSに関するエラーが出る事象については類似の投稿がありました。
https://teratail.com/questions/273401

以降はCORSが原因と推測しての回答となります。

Flutter Webとして動作させている場合、CORSによるエラーがしばしば問題になっているようです。
本エラーに似ている事象も見られるので同様の問題ではないかと推測しています。
https://github.com/dart-lang/http/search?q=cors&type=issues

CORSを対応or回避するにはいくつかあります。私が知る限りでは以下です。

  1. サーバ側に対応してもらう
  2. JSONP等CORSの制約を受けない方法を利用する
  3. 中継するAPIサーバを用意し、そこでCORSの制約を回避できるレスポンスを返すようにする
  4. ブラウザのセキュリティを落とす

まず、(1)ですが、それはホットペッパーAPI側にお願いする必要があるという意味なので、今回の場合はそれはまず難しいでしょう。

そうなると、類似の投稿で答えられている通り、(2)JSONPを使うか、(3)アプリのためにAPIを提供する自前のAPIサーバを用意してそのAPIサーバでホットペッパーAPIを扱う、といった回避の仕方が出てくるかと思います。

Flutter CORSで調べるとstackoverflowにて以下の投稿を見つけました。
https://stackoverflow.com/questions/65291888/flutter-web-http-error-uncaught-in-promise-error-xmlhttprequest-error/66072946

ここの回答では(3)と(4)の方法で対応しようとしています。

(3)はこちらの回答で、CORSに必要なヘッダをつけて返すサーバを動かすというやり方のようです。ただ実際にこれで運用してよいとは思えません。

(4)はこちらの回答で、Flutterのデバッグで表示する際のブラウザを起動する際に、CORSを無効化する手順に見えます。stackoverflowのコメントを見る感じでは、リスクについては述べられていないようです。
(単純にセキュリティを無効化した状態で他のサイトを見に行けるケースがあったら、それが危険だと思っています・・・私の理解が間違っているかもしれませんが・・・)

(2)はFlutter Webでの事例が見当たらなかったのでよくわかりません。ios/androidを考えるとJSONPはできない気もします。

長くなりましたが、まず切り分けの観点で試すなら(4)を試して解消するかどうかを確認するのが良いかと思います。しかし、そのまま運用するかどうかはよく考えたほうが良いと思います。利用者のブラウザのセキュリティを落として使ってもらうことになるからです。(実機デバッグが難しいのでWebをデバッグ環境で使う分にはいいかもしれません。)
実際に運用する場合は(3)のやり方ですが、回答にあるような単純なサーバをそのまま公開すると悪用される懸念があります。(3)の方法はちゃんと実装すれば、APIキーをクライアントから隠せるほか、キャッシュを返したり、自分の持っているデータと組み合わせた返し方もできるようになるので、面倒ですがいろいろ現実的ではあると思います。(他にいい方法があったら私も知りたいです。)

投稿2021/07/10 04:20

fukasawah

総合スコア147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問