ホームページ  >  記事  >  ウェブフロントエンド  >  クロスドメインの問題に対する非常に詳細な完全なソリューション (例付き)

クロスドメインの問題に対する非常に詳細な完全なソリューション (例付き)

不言
不言転載
2019-01-14 10:05:472520ブラウズ

この記事は、クロスドメインの問題に対する非常に詳細で完全な解決策を提供します (例を示します)。困っている友人が参考になれば幸いです。

クロスドメイン、一般的な問題

簡単な説明

フロントエンドの新人として、私は JSONP と CORS しか知りません。クロスドメインについては深く理解していませんでした。しかし、春の採用が近づくと、新人も羽ばたかなければなりません。私はここ数日、クロスドメインの問題を注意深く研究し、開発者の役に立つことを願ってこの記事を書きました。この記事を読む前に、次のことについてある程度の知識があることを願っています。

ブラウザオリジンポリシー

nodejs

iframe

docker、nginx

クロスドメインの問題を調査する必要がある理由

ブラウザの同一オリジン ポリシーでは、特定のドメインのクライアントが明示的な承認なしに別のドメインのリソースを読み書きできないと規定されているためです。実際の開発では、フロントエンドとバックエンドが互いに分離されていることが多く、フロントエンドとバックエンドのプロジェクトのデプロイメントがサーバー内にない、またはサーバーの異なるポート下にないことがよくあります。フロントエンドがバックエンドからデータを取得したい場合は、リクエストを開始する必要があります。リクエストが適切に処理されると、ブラウザーの同一生成元ポリシーによって制限されます。バックエンドはリクエストを受信して​​データを返すことができますが、フロントエンドはデータを受信できません。

複数のクロスドメイン手法

クロスドメインの目的は大きく分けて2つ

フロントエンドとバックエンドを分離する場合、フロントエンドはクロスドメインを使用します

異なるドメインでのフロントエンド ページ通信にクロスドメイン

フロントエンドとバックエンドの分離にクロスドメイン

Cross Origin Resource Share (CORS)

CORS は、一連のリクエスト ヘッダーとレスポンス ヘッダーを追加することで、クロスドメインの問題を解決するクロスドメイン リソース共有ソリューションです。 、クロスサイトのデータ送信は標準化されており安全です

Request ヘッダーには主に

Origin ヘッダーは、クロスドメイン内のクロスドメイン リクエストのソース ドメイン名を示します。リクエストまたは事前リクエスト。 Access-Control-Request-Method ヘッダーは、実際に使用される HTTP メソッドを示すために使用されます。クロスオリジンリクエスト Access-Control-Request-Headers は、サーバーに開始を通知するために使用されます。クロスドメインリクエストで伝送されるリクエストヘッダー情報
Request ヘッダー が含まれます。説明
# #Origin
Access-Control-Request-Method
Access-Control-Request-Headers
#応答ヘッダーには主に

が含まれます。

## 応答ヘッダー #説明##Access-Control-Allow-OriginAccess-Control-Allow-Origin ヘッダーには、サーバー側の検証後に許可されたクロスドメイン要求ドメイン名が含まれます。これは、特定のドメイン名または * (任意のドメイン名を示す) にすることができます。 Access-Control-Expose-Headers ヘッダーは、応答ヘッダーを返せるようにするために使用されます。クロスドメイン要求リストに含まれる応答ヘッダーの内容には、ブラウザからアクセスできます。 Access-Control-Max-Age は、事前の結果をブラウザーに伝えるために使用されます。 -check リクエストを返すことができます。 キャッシュ時間。キャッシュの有効期間中、ブラウザはキャッシュされた事前チェック結果を使用して、クロスドメイン リクエストを送信するかどうかを決定します。 Access-Control-Allow-Methods は、実際にクロス送信できることをブラウザーに伝えるために使用されます。 -domainrequests の場合、サポートされるリクエスト メソッドは、特定のメソッド リストまたは * (任意のメソッドを示す) です。

使用方法

  • クライアントは仕様に従ってリクエストヘッダを設定するだけです。

  • サーバーは、仕様に従って対応する応答ヘッダーを識別して返したり、対応するプラグインをインストールしたり、対応するフレームワーク構成ファイルを変更したりします。サーバーで使用される言語とフレームワークによって異なります

SpringBoot CORS 設定の例

Spring Boot での CORS 構成に関するコードプロジェクト

HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String temp = request.getHeader("Origin");
        httpServletResponse.setHeader("Access-Control-Allow-Origin", temp);
        // 允许的访问方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
//         Access-Control-Max-Age 用于 CORS 相关配置的缓存
        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
        httpServletResponse.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept,token");
        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");

JSONP クロスドメイン

jsonp の原理は、HTML で <script> タグを使用して、ドメイン間でリソースを導入することです。したがって、<srcipt> タグが動的に作成され、src はデータを処理する宛先インターフェイスの get data packet の関数名になります。 GET リクエストを受信した後、バックエンドは関数名 (データ) を解析し、フロントエンド<script> 処理関数を動的に実行します。<br/>次のコードを確認してください。 code</script>

nbsp;html>


    <meta>
    <title>Title</title>


<script>
    var script = document.createElement(&#39;script&#39;);
    script.type = &#39;text/javascript&#39;;

    // 传参并指定回调执行函数为getData
    script.src = &#39;http://localhost:8080/users?username=xbc&callback=handleData&#39;;
    document.body.appendChild(script);
    // 回调执行函数
    function handleData(res) {
        data = JSON.stringify(res)
        console.log(data);
    }
</script>

バックエンド コード (nodejs)

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    var params = querystring.parse(req.url.split('?')[1]);
    var fn = params.callback;

    // jsonp返回设置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    var data = {
        user: 'xbc',
        password: '123456'
    }
    res.write(fn + '(' + JSON.stringify(data) + ')');

    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

この例では、フロント デスクが受信する応答は次のようになります


クロスドメインの問題に対する非常に詳細な完全なソリューション (例付き) #フロントエンドページは次のとおりです

##注意クロスドメインの問題に対する非常に詳細な完全なソリューション (例付き)

以来JSONP は を使用するため、GET リクエストのみをサポートします。他のリクエストは実装できませんnginx リバースプロキシはクロスドメインを実現します

アイデア

ブラウザには同一オリジンポリシー制限があるため、次のようにします。フロントエンドプロジェクト フロントエンドが要求する API インターフェースのアドレスを同じオリジンに置くだけでは十分ではないでしょうか? Web サーバーが提供するリバース プロキシと組み合わせることで、フロントエンドまたはバックエンドでの構成を行わずに、クロスドメインの問題を解決できます。 nginx を例に挙げます

バックエンドの実際のバックグラウンド アドレス:

http://xxx.xxx.xxx.xxx:8085

バックエンド アドレスは Spring を使用します。 Tomcat によってデプロイされたブート プロジェクト 名前は

gsms_test

nginx サーバー アドレス: http://xxx.xxx.xxx.xxx:8082

両方の Tomcatとnginxを使用します dockerでセットアップし、ポートフォワーディングを行います利用条件: 開発環境はLinuxシステム

nginx

/etc/nginx/conf.d/defaultです。 conf

構成コードは次のとおりです

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        # root   /usr/share/nginx/html/dist; # 前端项目路径
        # index  index.html index.htm;
        proxy_pass http://localhost:8001/; # 前端本机地址,实现自动更新
        autoindex on;
        autoindex_exact_size on;
        autoindex_localtime on;
    }

    location /gsms_test/ {
        proxy_pass 后端真实地址;
    }

    

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

異なるドメインのページはドメイン間で通信します

window.name iframe クロスドメイン

window.name は参照中です。サーバー内のウィンドウによって共有されているデータは、別のページ (または別のドメイン名) に読み込まれた後も引き続き存在します (変更されなければ値は変わりません)。とても長い 名前の値 (2MB)。例えば ドメイン a のページがドメイン b のページからデータを取得したい場合は、ドメイン b の window.name 値を変更します。ドメイン a をドメイン b に切り替えて、再度切り替えてドメイン b の window.name 値を取得します。ただし、開発中にページを前後に切り替えることは絶対に避けたいので、それを実現するには iframe を組み合わせる必要があります。

例 (thinkjs で実装)

a ドメイン コードは次のとおりです

nbsp;html>


<meta>
<title>A 域</title>


<h1>server A</h1>
<script>
    function getData() {
        var iframe = document.getElementById(&#39;proxy&#39;);
        iframe.onload = function () {
            var name = iframe.contentWindow.name; // 获取iframe窗口里的window.name值
            console.log(name)
        }
        // 由于iframe信息传递也受同源策略限制,所以在window.name被B域修改后,将iframe转回A域下。以便获取iframe的window.name值
        iframe.src = &#39;http://127.0.0.1:8360/sub.html&#39; 
    }
</script>
<iframe>        </iframe>

b ドメイン コード

nbsp;html>


<meta>
<title>New ThinkJS Application</title>


  <h1>server 2</h1>
<script>
  window.name = &#39;user: xbc&#39;;
</script>

Note

同一オリジン ポリシーの制限により、親ページはクロスドメイン iframe ページから不完全な情報を取得するため、iframe の window.name が変更された後。 B ドメインの場合は、A ドメインの下の任意のページに変換する必要があり (Window.name はこの側で変更しないでください)、取得されます。

プロキシ ページ iframe でクロスドメイン アクセスを実現

iframe と親ページ間の相互アクセスも同一オリジン ポリシーによって制限されるため、クロスドメイン アクセスを実現するにはプロキシ ページが必要です。

クロスドメインの問題に対する非常に詳細な完全なソリューション (例付き) 個人的には少し面倒だと思いますが、興味があればフロントエンドがプロキシ ページをどのように使用するかをご覧ください。 iframe のクロスドメイン アクセスの問題は解決しますか?

概要

上記はすべて、私が使用またはテストしたクロスドメイン メソッドです。postMessage や WebSocket などのクロスドメイン メソッドもあります。説明なしに連絡したことはありません。プロジェクトで具体的にどの方法を使用するかについても、さまざまな問題を考慮する必要があります

状況
Access-Control-Expose-Headers
Access-Control-Max-Age
Access-Control-Allow-Methods
方法GET リクエストのみJSONP#互換性とブラウザのバージョンに関する要件なし#互換性とブラウザのバージョンに関する要件iframe またはサーバー リバース プロキシ (Linux 環境で開発)
#CORS

以上がクロスドメインの問題に対する非常に詳細な完全なソリューション (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。