개발하자

다트 코드로만 플러터 웹 API 오류를 해결하는 방법은 무엇입니까?

Cuire 2022. 12. 15. 12:54
반응형

다트 코드로만 플러터 웹 API 오류를 해결하는 방법은 무엇입니까?

CORS 오류는 웹 분야에서 잘 알려진 문제인 것 같습니다. 하지만 나는 처음으로 플러터 웹을 시도했고 치명적인 오류에 직면했다.

아래 코드는 iOS 기기에서 실행할 때 앱 버전에서는 잘 작동했지만, 크롬에서 베타 채널에서 웹 디버깅으로 동일한 코드를 테스트했을 때 CORS 오류가 발생했습니다.

다른 스택 오버플로 답변에서는 프로젝트의 서버 측 파일을 사용하여 CORS 문제를 해결하는 방법을 설명했습니다. 하지만 나는 서버가 무엇이고 그들의 대답을 어떻게 처리해야 하는지 전혀 모른다. Chrome 콘솔의 오류 메시지는 다음과 같습니다.

[ 오리진 'host://localhost:52700'에서 'https://kapi.kakao.com/v1/payment/ready'의 XMLHttpRequest에 대한 액세스가 CORS 정책에 의해 차단되었습니다. 사전 비행 요청에 대한 응답이 액세스 제어 검사를 통과하지 못함: 요청한 리소스에 'Access-Control-Allow-Origin' 헤더가 없습니다. ]

그래서 내가 하고 싶은 것은 위의 'Access-Control-Allow-Origin header' 문제를 DART CODE로만 해결하는 것이다! 아래 코드는 내 main.dart로만 이 문제들을 해결하려고 노력한 것이다.

onPressed: () async {
      var res =
          await http.post('https://kapi.kakao.com/v1/payment/ready', encoding: Encoding.getByName('utf8'), headers: {
        'Authorization': 'KakaoAK $_ADMIN_KEY',
        HttpHeaders.authorizationHeader: 'KakaoAK $_ADMIN_KEY',
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE, HEAD",
      }, body: {
        'cid': 'TC0ONETIME',
        'partner_order_id': 'partner_order_id',
        'partner_user_id': 'partner_user_id',
        'item_name': 'cool_beer',
        'quantity': '1',
        'total_amount': '22222',
        'vat_amount': '2222',
        'tax_free_amount': '0',
        'approval_url': '$_URL/kakaopayment',
        'fail_url': '$_URL/kakaopayment',
        'cancel_url': '$_URL/kakaopayment'
      });
      Map<String, dynamic> result = json.decode(res.body);
      print(result);
    },

실제로 대부분의 다른 답변에서 권장하는 헤더가 있었지만 크롬 콘솔은 동일한 오류 메시지를 출력했습니다. 이상한 것은 같은 코드가 모바일 앱 버전에서 성공적인 요청을 했다는 것이다. 그래서 나는 이것이 오직 flotWEB Version의 문제라고 생각한다.

누군가가 그것을 알아내고 내 메인.dart에서 문제를 해결하기 위해 오직 다트 코드를 제안할 수 있기를 바란다!! 읽어주셔서 감사합니다 [:




Flower 3.3.0 이후

나는 펄럭이는 명령에 따른다.

flutter run -d chrome --web-browser-flag "--disable-web-security"

또는 명령의 경우:

flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d web-server --web-browser-flag="--disable-web-security"



비활성화된 웹 보안 접근법은 개발에서는 잘 작동하지만 프로덕션에서는 잘 작동하지 않을 수 있습니다. 프로덕션 다트 코드에서 나에게 효과적인 접근법은 웹 요청을 단순하게 유지함으로써 비행 전 CORS 검사를 완전히 피하는 것을 포함한다. 나의 경우, 이것은 다음을 포함하도록 요청 헤더를 변경하는 것을 의미했다.

'Content-Type': 'text/plain'

제가 실제로 json을 보내더라도 text/plain으로 설정하면 비행 전 CORS 검사를 피할 수 있습니다. 제가 호출하는 람다 기능은 비행 전 옵션 요청을 지원하지 않습니다.

다음은 비행 전 요청을 피하는 다른 방법에 대한 몇 가지 정보입니다.




이는 CORS(교차 오리진 리소스 공유) 문제이므로 아무것도 삭제하거나 수정할 필요가 없습니다. 서버 측에서 CORS 요청을 활성화하기만 하면 잘 작동할 것입니다.

나의 경우, 나는 node.js와 express.js로 서버를 만들어서 모든 요청에 대해 실행될 미들웨어 기능을 추가했다.

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,PUT,PATCH,POST,DELETE");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

그리고 BOOOM! 나는 데이터를 받았다.

당신은 당신의 서버에 CORS를 활성화하기 위한 설정을 보기만 하면 된다.




몇 시간 동안의 테스트 후에, 다음은 나에게 완벽하게 적용된다.

PHP 파일에 다음을 추가합니다.

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");

이를 통해 HTTP GET POST와의 올바른 연결이 가능합니다.

나는 다음 토론에서 이것을 발견했다:

XMLHttpRequest 오류가 발생했습니다.




아래 솔루션은 로컬 노드와만 통신하는 경우에 유용합니다.JS 서버.

  1. 설치 노드JS
  2. 기본 NodeJS Express 프로젝트 생성
// init express
const express = require("express");
const app = express();

// set the path to the web build folder
app.use(express.static("C:/Users/your_username/path_to_flutter_app/build/web"));

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
    console.log(`Server listening on port ${PORT}...`);
});
  • 이 값은 플러터 앱의 웹 빌드 폴더로 변경해야 합니다.
  • 앱이 구축되고 노드 서버가 실행되고 브라우저가 올바른 주소에 있으면 브라우저를 통해 앱에 액세스할 수 있습니다.

플래터 앱의 다트 코드를 변경할 때마다 다시 실행해야 합니다.




대상 포트 🤦의 잘못된 서버

이것을 인정하는 것조차 바보 같은 기분이 들지만, 대상 포트에서 다른 로컬 서버를 실행했습니다. 서버가 왜 같은 포트에서 부팅되는 것처럼 보였는지, iOS 앱이 작동하는 것처럼 보였는지 전혀 모르겠지만, 이제 실제 서버에 접속하니 잘 작동하고 있다.

나도 404개를 섞고 있었는데, 원래는 CORs 오류 때문인 줄 알았어.

아마도 다른 사람이 이 같은 문제를 가지고 있고 이것이 그들에게 도움이 될 것이다.




나의 경우 CORS를 지원하지 않는 라벨 백엔드 코드에 문제가 있어 백엔드 프로젝트에 CORS를 추가한 후 테스트 및 라이브에서 성공적으로 작동했습니다.




나는 php api에서 같은 오류를 받고 있어서 이 줄들에 php 코드를 추가한다;

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");



의 다섯 번째 단계는 옵션을 추가하는 것입니다.

'--disable-site-messages',

오직 이것만이 나에게 효과가 있다.

크롬 버전 106.0.5249.119




안녕하세요. 오류가 존재하지 않는 헤더에 대해 설명합니다. 그래서 당신의 서버는 이미 코르스에 대해 설정되어 있을 수 있다. 제 오류는 다음과 같습니다. 오류: XMLHttpRequest 오류입니다. C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 963:28 현재 패키지/http/src/b/browser_client.dart 69:22 C:22 C:/b/b/s/b/b/s/s/s/b/b/b/b/b/b/b/b/b/b/b/b/b/b/candleValue C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/asy/future_impl.dart 766:44 handleValueCallback C:/b/debug/debug/debug/dbuilder/debug/debug/dbuilder/db/w/w/w/w/w/w/w/host_chew/w/w/host_chew/db/der/src/out/host_debug/dart-sdk/lib/async/stream_pipe.dart 61:11_cancelAndValue C:/b/s/w/cache/builder/src/out/host_debug-s/ddebug/s/drun/internal_db/s.debug-s/s/s/c/db/c/w/c/b/b/b/b/b/b/c/c/stream_c/c/cdart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 339:39 dcall C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/html_dart2js.dart2js.dart 37309:58

at Object.createErrorWithStack (http://localhost:1681/dart_sdk.js:5093:12)
at Error._throw (http://localhost:1681/dart_sdk.js:20399:18)
at Error.throwWithStackTrace (http://localhost:1681/dart_sdk.js:20396:18)
at async._AsyncCallbackEntry.new.callback (http://localhost:1681/dart_sdk.js:40921:18)
at Object._microtaskLoop (http://localhost:1681/dart_sdk.js:40778:13)
at _startMicrotaskLoop (http://localhost:1681/dart_sdk.js:40784:13)
at http://localhost:1681/dart_sdk.js:36261:9

응 그것은 잘 알려진 문제인 것처럼 보인다. 하지만 내가 웹에서 얻는 모든 대답은 디버그에서만 작동하거나 전혀 작동하지 않는다. 제가 파악할 수 있는 한 당신은 당신의 서버 쪽에서 그것을 활성화해야 한다. 운영 웹 앱이 작동할 수 있도록 서버 측에서 활성화하는 방법을 아는 사람이 있습니까? 직접 관리자가 있는 Apache를 실행합니다. PC에서 로컬이 아닌 온라인에서. 임시 솔루션을 찾는 것이 아니라 운영 중에 작동할 솔루션을 찾는 것입니다. 감사해요.




나는 네가 이것을 제대로 하지 못할 수도 있다고 생각한다. 요청 헤더에 추가한 cors 헤더는 HTTP 응답 헤더에 추가해야 합니다.

자세한 내용은 설명서를 참조하십시오.




1 - 다음 이름의 파일로 이동하여 제거합니다.

2- 파일로 이동하여 엽니다.

3 - 찾기

4 - 추가




노드 js 또는 django와 같은 서버 사이드 엔진은 외부 아피스가 많은 플러터 웹으로 작업하기 위해 정말로 필요하다. 실제로 포트 번호 차이와 관련된 CORS 메커니즘 때문에 내부 api를 사용하려고 할 때 동일한 CORS 오류가 발생할 가능성이 높습니다.

CORS 오류를 피하기 위해 크롬 확장을 사용할 것을 권장하는 SO 기고자들의 단계와 답변이 많지만, 그것은 사실 사용자들에게 쿨하지 않다. 모든 사용자는 단일 웹 사이트를 사용하기 위해 브라우저 확장을 다운로드해야 합니다. 우리가 진정한 서버 엔진을 사용한다면 없을 것입니다.

내가 알기로는 CORS는 브라우저에서 나온 것이기 때문에 같은 API 코드를 가진 우리의 flotios와 안드로이드 앱은 CORS 오류를 발생시키지 않는다. 처음으로 펄럭이는 웹에서 이 오류를 만났을 때, 나는 내 앱 코드 라인에서 CORS를 다룰 수 있다고 믿었다. 그러나 그것은 실제로 사용자와 장기 개발 계획에 건강한 방법이 아니다.

Hope all flutter web newbies understand that web is quite a wild field for us. Even though i'm also newbie here, i highly recommend all the flutter web devs from 1.22.n stable to learn server side engines like node js. It is worth try.

And if u came so far down to this line of my self-answer, here's a simple guide for flutter web with node js. Flutter web is on stable channel but all those necessary infra are not fully ready for newbies like me. So be careful when you first dive into web field, and hope you re-check all the conditions and requirements to find out if you really need web version of your flutter app, and also if you really need to do this work with flutter. And my answer was yes lol

https://blog.logrocket.com/flutter-web-app-node-js/




If you run a Spring Boot server, add "@CrossOrigin" to your Controller or to your service method.

@CrossOrigin
@PostMapping(path="/upload")
public @ResponseBody ResponseEntity<Void> upload(@RequestBody Object object) {
    // ...
}

I know the question explicitly asked for a solution "with dart code" only, but I was not able to fix the exception with dart code (for example by changing the header).




Update

I recommend to use Rexios's answer. His package makes it very convenient to modify the Flutter source code.


Alternative solution for MacOS & Android Studio (without modifying Flutter source)

We use a similar approach as Osman Tuzcu. Instead of modifying the Flutter source code, we add the --disable-web-security argument in a shell script and just forward all other arguments that were set by Flutter. It might look overly complicated but it takes just a minute and there is no need to repeat it for every Flutter version.

1. Run this in your terminal

echo '#!/bin/zsh
# See also https://stackoverflow.com/a/31150244/410996
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
set -e ; /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --test-type --disable-web-security "$@" ; set +e &
PID=$!
wait $PID
trap - SIGINT SIGTERM EXIT
wait $PID
' > ~/chrome_launcher

chmod 755 ~/chrome_launcher

This adds a chrome_launcher script to your user folder and marks it executable.

2. Add this line to your .zshrc (or .bashrc etc.):

export CHROME_EXECUTABLE=~/chrome_launcher

3. Restart Android Studio

If a simple restart does not work, use Invalidate Caches / Restart in Android Studio to force loading of changes.

Notes

The script also adds the --test-type flag to suppress the ugly warning about the disabled security features. Be aware that this option might also suppress other error messages! The CHROME_EXECUTABLE takes only the path to an executable file it is not possible to set arguments there. Without trapping exit signals and killing the process group, the Google Chrome instance was not killed when you hit the Stop Button in Android Studio.




Using Osman Tuzcu's answer, I created flutter_cors to make the process easier.




run/compile your Flutter web project using web-renderer. This should solve the issue both locally and remotely:

flutter run -d chrome --web-renderer html
flutter build web --web-renderer html



https://docs.flutter.dev/development/platform-integration/web-images

flutter run -d chrome --web-renderer html
flutter build web --web-renderer html



This official solution worked for me on Chrome only (Source). But I had to run it first every time.

flutter run -d chrome --web-renderer html

And disabling web security also worked (Source). But the browsers will show a warning banner.

But In case you are running on a different browser than Chrome (e.g. Edge) and you want to keep 'web security' enabled. You can change the default web renderer in settings in VS Code

File ==> Preferences ==> Settings ==> Enter 'Flutter Web' in the Search Bar ==> Set the default web renderer to html




I think disabling web security as suggested will make you jump over the current error for now but when you go for production or testing on other devices the problem will persist because it is just a workaround, the correct solution is from the server side to allow CORS from the requesting domain and allow the needed methods, and credentials if needed.


반응형