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

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

ただいまの
回答率

90.51%

  • Node.js

    2360questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • Express

    301questions

    ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

  • Angular

    177questions

  • CORS

    36questions

    CORSとはCross-Origin Resource Sharingの頭文字をとったもので、ブラウザがオリジン以外のサーバからデータを取得するシステムのことです。

Angualr の express で CORS 許可ができない

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 230

to33y

score 0

前提・実現したいこと

Angular (v7) + Express (v4) で Web アプリをローカルマシンで開発しています。

OAuth を利用した認証付きのサイトにするために、 CORS に対応したロジックにしようとしており、
認証に関わる API が呼ばれたら OAuth の認証ページにリダイレクトする機構にしようとしています。

ひとまずは、特定の API が呼ばれた時に、 一旦 OAtuh とは全く関係無い別のよく知られたサイト (今回は Yahoo Japan に飛ばそうとしてます。) にリダイレクトだけさせてみようとしているのですが、
どうしても Chrome のコンソールで以下のエラーが出力されて、リダイレクト先に遷移が行われません。

(尚、認証をしなければ、既存の内部の API 通信処理は問題なく意図した動作ができることを確認しており、あとは認証機構だけ入れれば完了という状態になっています。)

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

動作確認 Web ブラウザは Chrome です。

ブラウザの開発者ツール「Console」の結果

ブラウザコンソールに以下のコンソールログが吐かれてます。

  • Error ログ
Access to XMLHttpRequest at 'https://www.yahoo.co.jp/' (redirected from 'http://localhost:3000/api/auth') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  • たて続けに出ている Warn ログ
Cross-Origin Read Blocking (CORB) blocked cross-origin response https://www.yahoo.co.jp/ with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.
ブラウザの開発者ツール「Network」の結果
  • http://localhost:3000/api/auth の結果(後述の試したパターンの内の一例)
【General】
Request URL: http://localhost:3000/api/auth
Request Method: GET
Status Code: 302 Found
Remote Address: [::1]:3000
Referrer Policy: no-referrer-when-downgrade

【Response Headers】
Access-Control-Allow-Origin: *
Connection: keep-alive
Content-Length: 46
Content-Type: text/plain; charset=utf-8
Date: Thu, 14 Mar 2019 08:54:36 GMT
Location: https://www.yahoo.co.jp/
Vary: Accept
X-Powered-By: Express

【Request Headers】
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Connection: keep-alive
Content-Type: application/json
Host: localhost:3000
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
  • https://www.yahoo.co.jp の結果
【General】
Request URL: https://www.yahoo.co.jp/
Request Method: OPTIONS
Status Code: 200 
Remote Address: 183.79.250.251:443
Referrer Policy: no-referrer-when-downgrade

【Request Headers】
Provisional headers are shown
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: GET
Origin: http://localhost:3000
Referer: http://localhost:3000/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36

該当のソースコード

クライアント側

クライアントの API 呼び出しは以下のサービスクラスで実行。CORS の対応は、クライアント側は特に無い認識です。

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams, HttpResponse, HttpErrorResponse } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class HttpService {

  constructor(protected http: HttpClient) { }

  // API 呼出メソッド (GET)
  private async get(): Promise<any> {
    try {
      const url = 'http://localhost:3000/api/auth';
      const httpParams: HttpParams = new HttpParams();

      // HTTP通信 実行
      const response = await this.http.request<Res>(method, url, {
        headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
        responseType: 'json',
        params: httpParams
      }).toPromise();

      return { ok: true, status: 200, body: response };
    } catch (error) {
      return { ok: false, body: undefined };
    }
  }
}

サーバ側

こっちで CORS 対応を頑張れば良い認識。
以下の3種類のソースで試してみてますが、いずれも全く同じエラーでうまくいきません。

パターン1:ワイルドカードで全て CORS 許可

レスポンスヘッダは、ベタ書き

import * as express from 'express';
import * as bodyParser from 'body-parser';
import { join } from 'path';

const app = express();

// CORS 対応 (ベタ書き)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, application/json, Accept, x-client-key, x-client-token, x-client-secret, Authorization');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  next();
});

// API ルーティング提供 (一応 ボディパーサも対応)
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '100kb' }));
app.get('/api/auth', (req, res) => {
  res.redirect('https://www.yahoo.co.jp/');
});

// クライアント静的ファイル提供
app.use(express.static(join(process.cwd(), 'dist/my-web-app')));

// アプリ起動
app.listen(3000);
パターン2:Origin を2サイト明示して、 更にヘッダに "Credentials: True" を設定

こちらもレスポンスヘッダは、ベタ書き

import * as express from 'express';
import * as bodyParser from 'body-parser';
import { join } from 'path';

const app = express();

// CORS 対応 (ベタ書き)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000, https://www.yahoo.co.jp/');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, application/json, Accept, x-client-key, x-client-token, x-client-secret, Authorization');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  res.header('Access-Control-Allow-Credentials', 'true');
  next();
});

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '100kb' }));
app.get('/api/auth', (req, res) => {
  res.redirect('https://www.yahoo.co.jp/');
});

app.use(express.static(join(process.cwd(), 'dist/my-web-app')));

app.listen(3000);
パターン3:npm パッケージ「cors」を利用
import * as cors from 'cors'; // 追加
import * as express from 'express';
import * as bodyParser from 'body-parser';
import { join } from 'path';

const app = express();

// CORS 対応 (全て CORS 許可する設定で利用)
app.use(cors());

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '100kb' }));

app.get('/api/auth', (req, res) => {
  res.redirect('https://www.yahoo.co.jp/');
});

app.use(express.static(join(process.cwd(), 'dist/my-web-app')));

app.listen(3000);

上記の3パターンを試しても、CORS 対応はできず、他のネット記事をみても同じような対応しか見当たらない状況です。

どなたか原因または解消方法がわかる方はいますでしょうか?

補足情報(FW/ツールのバージョンなど)

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

私もcorsはまだまだ悩みながら対応している状態なので、的はずれな回答をしていたらすみません。

今テストされているケースですと、

Yahoo Japan側が Access-Control-Allow-Origin に localhost:3000を追加してくれないと、
CORSのエラーで引っかかるのではないかと思いました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • Node.js

    2360questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • Express

    301questions

    ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

  • Angular

    177questions

  • CORS

    36questions

    CORSとはCross-Origin Resource Sharingの頭文字をとったもので、ブラウザがオリジン以外のサーバからデータを取得するシステムのことです。