78259


chrome extension 内で取得した文字列をローカルのファイルに書き込みがしたいです

* * *

javascript のセキュリティ的に直接書き込む方法がなさそうなので  
ローカルにリクエスト内容をファイルに書き込みするだけでのウェブサーバーを立てて  
そこへ POST するようなコードを chrome extension 内で書いたんですが

[code]

    has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    
[/code]

というエラーになります

CORS というものがあることは知ってたんですが  
正確に仕様を把握できていなくて  
なんとなくアクセスしてるサーバー以外にリクエストを投げることを禁止しようとしてるエラーに見えるんですが、  
`<script src="">` とかを HTML で外部CDNから中身を取ってくるっていうのは普通にやれると思うし  
google analytics とかはぜんぜん関係ないサイトの情報を google に送信できたりしますよね  
どういうケースだとブロックされるんでしょうか

javascript 上の文字列をローカルホストに送信するにはどうすればいいのでしょうか

以下  
<https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data>  
を参考にした chrome-extension 内のコードです

[code]

    // data に送信したいテキストが入っている状態
    
                var oReq = new XMLHttpRequest();
                oReq.open("POST", 'http://localhost:4000/', true);
                oReq.onload = function (oEvent) {
                  // Uploaded.
                };
    
                var blob = new Blob([data], {type: 'text/plain'});
    
                oReq.send(blob);
    
[/code]


CC BY-SA 4.0
2021-07-17T13:00:12.280
78256
2021-07-19T18:20:02.723
2021-07-17T16:09:44.100
3060
question
javascript http chrome-extension cors
CORS policy とは何ですか？


CORS が何なのか、どういう場合にブロックされるのか事については、 MDN でとても詳しく書かれているので、こちらを読んでいただくのがイチバンです。  
<https://developer.mozilla.org/ja/docs/Web/HTTP/CORS/Errors>  
<https://developer.mozilla.org/ja/docs/Web/HTTP/CORS>

実際にどういった場合に制限されるのかは、 ブラウザーやバージョンによって異なるので、一概には説明できません。  
上記の記事にあるように、実際にエラーが発生した場合、開発者コンソールにエラーが表示されるので、遭遇した原因は調査できますね。

* * *

で、ご質問のパターンの場合、エラー文に書かれているとおり、 リクエストされるサーバーが `'Access-Control-Allow-Origin'`
ヘッダーを返せば OK です。

ローカルに立てておられるウェブサーバーを何で書いているかわかりませんが、 とりあえず node.js で例を出してみましょう。  
以下のような感じで POST されたデータをオウム返しするサーバーを http://localhost:4000/ に立てました。

[code]

    const http = require("http");
    
    const server = http.createServer((req, res) => {
        if (req.method === 'POST') {
            let data = '';
            res.setHeader('Content-Type', 'text/plain');
            res.setHeader('Access-Control-Allow-Origin', '*');
            req.on('readable', (chunk) => {
                let data_t = req.read();
                if (data_t) data += data_t;
            });
            req.on('end', () => {
                res.end('post data is:' + data);
            });
        } else {
            res.statusCode = 404;
            res.end('NotFound')
        }
    });
    server.listen(4000);
    
[/code]

拡張機能側では、コンテンツスクリプトとしてフォアグラウンド側で実行されることを前提に、ページロード後 500ms 後に POST
叩いてそのレスポンスをコンソールに出力してみます。  
XMLHttpRequest を書き慣れていないので、 fetch を使った例となっている点ご容赦願います。  
fetch を使用する場合、 mode オプションにて CORS を明示する必要があります。

[code]

    (() => {
      'use strict';
      const sleep = msec => new Promise(resolve => setTimeout(resolve, msec));
      window.onload = async () => {
        await sleep(500);
    
        const res = await fetch("http://localhost:8000/", {
          method: "POST",
          mode: "cors",
          body: "FooBar",
        });
    
        console.log(await res.text());
      };
    })();
    
[/code]

これで、サーバ側で加工されたテキストが、ブラウザのテキストコンソールに現れていれば、成功です！

今回は、コンテンツスクリプトでの動作確認を行っていますが、おそらくイベントページやバックグラウンドページでも同じように動くと思われます。  
（もしかしたら、マニフェスト側で権限を追加する必要があるかも？）


CC BY-SA 4.0
2021-07-17T16:29:43.980
78259
2021-07-17T16:29:43.980
8237
78256
answer


> javascript 上の文字列をローカルホストに送信するにはどうすればいいのでしょうか

質問文に書かれているコードであれば「送信」は行えているはずです。  
従って期待通りサーバはリクエストを受け取っているはずです。

ブロックされているのは「JavaScriptでのレスポンス受信」です。

* * *

> どういうケースだとブロックされるんでしょうか

  * リクエストするがレスポンス受信をブロックする
  * リクエスト自身をブロックする(この場合もちろん受信もできない)

の2種類があります。

前者は、CORSが許可されていない状況で[単純リクエスト](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#simple_requests)を行う場合です。  
質問文のコードはこれに当てはまります。  
CORSを許可するためには、質問文中のエラーメッセージにある通り、 `localhost` サーバがレスポンスヘッダに `Access-Control-
Allow-Origin` を適切に設定する必要が有ります。  
(ただし今回の目的はサーバにリクエストを送信することだと思いますので、エラーが出たままでも目的は達成できていると思います。)

後者は、CORSが許可されていない状況で単純リクエスト **ではない** リクエストを行う場合です。  
単純リクエストと異なり、実際の送信を行う前に[プリフライトリクエスト](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#preflighted_requests)でCORSが許可されているかどうかを確認します。  
従って、`localhost`サーバが適切にプリフライトリクエストに応答しなければ送信自体が行われません。

* * *

> `<script src="">` とかを HTML で外部CDNから中身を取ってくるっていうのは普通にやれる

same-origin policyによって許可されているためです。  
[同一オリジンポリシー >
異なるオリジンへのネットワークアクセス](https://developer.mozilla.org/ja/docs/Web/Security/Same-
origin_policy#cross-origin_network_access):

> 以下に挙げるのは、異なるオリジンに埋め込むことができるリソースの例です。(中略)
>
>   * JavaScript を `<script src="..."></script>` で使用する場合。(後略)
>

ただし[`Cross-Origin-Resource-Policy`
レスポンスヘッダ](https://developer.mozilla.org/ja/docs/Web/HTTP/Cross-
Origin_Resource_Policy_\(CORP\))で制御可能です。

> google analytics とかはぜんぜん関係ないサイトの情報を google に送信できたり

Google Analyticsへのリクエストは単純リクエストで、かつレスポンスヘッダに適切な `Access-Control-Allow-Origin`
が付与されていると思います。


CC BY-SA 4.0
2021-07-17T17:26:31.387
78260
2021-07-19T18:20:02.723
2021-07-19T18:20:02.723
2808
2808
78256
answer