技術共有

フロントエンドのクロスドメインを徹底的に理解する

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

 

目次

1ブラウザの同一オリジンポリシー

1.1 同一生成元ポリシーの概要

1.2 起源とは何ですか?

2. クロスドメイントランザクションにはどのような制限がありますか?

2.1 DOM アクセスを制限する

2.2 Cookie へのアクセスを制限する

2.3 データ取得にAjaxを制限する

3つの注意点

4CORS は Ajax クロスドメインの問題を解決します

4.1CORSの概要

4.2CORS は単純なクロスドメインリクエストを解決します

4.3 単純なリクエストと複雑なリクエスト

4.4CORS は複雑なクロスドメインリクエストを解決します

4.5 cors ライブラリを使用して構成を迅速に完了する

5JSONP はクロスドメインの問題を解決します

6クロスドメインの問題を解決するためにプロキシを構成する

6.1 プロキシサーバーを自分で設定する

6.2 Nginx を使用してプロキシ サーバーを構築する

6.3 スキャフォールディングを利用してサーバーを構築する


コードアドレス git clone https://gitee.com/childe-jia/cross-domain-test.git

1ブラウザの同一オリジンポリシー

1.1 同一生成元ポリシーの概要


同一生成元ポリシーは、リソースのセキュリティを確保するためにブラウザが従うポリシーです。このポリシーは、リソースへのアクセスにいくつかの制限を課します。
W3C の同一オリジン ポリシーの説明:同一生成元ポリシー

1.2 起源とは何ですか?


1 ソースコンポーネント

画像.png


2 以下の表では、最後の行の 2 つのソースのみが同じ起源を持っています。

ソース1

ソース2

相同ですか?

http://www.xyz.com/ホーム

https://www.xyz.com/home

⛔非均質️

http://www.xyz.com/ホーム

http://mail.xyz.com/home

⛔不均質

http://www.xyz.com:8080/home

http://www.xyz.com:8090/ホーム

⛔不均質

http://www.xyz.com:8080/home

http://www.xyz.com:8080/検索

✅出身地が同じ︎

 

3 オリジンリクエスト

画像.png


4 オリジナルでないリクエスト

画像.png


5 要約: 「ソース」が「ターゲット ソース」と一致しない場合、それは「非ソース」を意味し、「ヘテロソース」または「クロスドメイン」とも呼ばれます。

2. クロスドメイントランザクションにはどのような制限がありますか?


たとえば、「ソース A」と「ソース B」という 2 つのソースがあり、それらが「同じオリジンではない」場合、ブラウザには次の制限があります。

2.1 DOM アクセスを制限する

「ソース A」のスクリプトは「ソース B」の DOM にアクセスできません。

  1. <!-- <iframe id="framePage" src="./demo.html"></iframe> -->
  2. <iframe id="framePage" src="https://www.baidu.com"></iframe>
  3. <script type="text/javascript" >
  4. function showDOM(){
  5. const framePage = document.getElementById('framePage')
  6. console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
  7. }
  8. </script>

2.2 Cookie へのアクセスを制限する

「ソース A」は「ソース B」の Cookie にアクセスできません

  1. <iframe id="baidu" src="http://www.baidu.com" width="500" height="300"></iframe>
  2. <script type="text/javascript" >
  3. // 访问的是当前源的cookie,并不是baidu的cookie
  4. console.log(document.cookie)
  5. </script>

2.3 データ取得にAjaxを制限する

「ソース A」は「ソース B」にリクエストを送信できますが、「ソース B」からの応答データを取得することはできません。

  1. const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
  2. let result = await fetch(url)
  3. let data = await result.json();
  4. console.log(data)

注: 上記の制限のうち、ブラウザによる Ajax データ取得の制限が最も影響が大きく、実際の開発では頻繁に遭遇します。

3つの注意点

  • 1クロスドメイン制限はブラウザ側にのみ存在し、サーバー側にはクロスドメイン制限はありません。
  • 2 クロスドメインでもAjaxリクエストは正常に発行できますが、レスポンスデータは開発者に引き継がれません。
  • 3<link> 、 <script>、<img>...... 这些标签发出的请求也可能跨域,只不过浏览器对标签跨域不做严格限制,对开发几乎无影响

画像.png

4CORS は Ajax クロスドメインの問題を解決します

4.1CORSの概要

CORS の正式名: Cross-Origin Resource Sharing (Cross-Origin Resource Sharing) は、クロスドメイン要求のブラウザー検証を制御するために使用される一連の仕様です。サーバーは CORS 仕様に従い、ブラウザー検証を制御するための特定の応答ヘッダーを追加します。一般的なルールは次のとおりです。
●サーバーがクロスドメインリクエストを明示的に拒否するか、それを示さないため、ブラウザは検証に失敗します。
●サーバーはクロスドメイン要求が許可されていることを明確に示しており、ブラウザーの検証に合格します。
注: CORS を使用してクロスドメインの問題を解決するのは最もオーソドックスな方法であり、サーバーが「独自の」サーバーである必要があります。


4.2CORS は単純なクロスドメインリクエストを解決します

全体的な考え方: サーバーが応答すると、Access-Control-Allow-Origin 応答ヘッダーを追加することで、特定のソースがクロスドメイン リクエストの開始を許可されていることを明確に表現し、ブラウザーは検証中にそれを直接渡します。

画像.png

サーバー側のコア コード (Express フレームワークを例にします):

  1. // 处理跨域中间件
  2. function corsMiddleWare(req,res,next){
  3. // 允许 http://127.0.0.1:5500 这个源发起跨域请求
  4. // res.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500')
  5. // 允许所有源发起跨域请求
  6. res.setHeader('Access-Control-Allow-Origin','*')
  7. next()
  8. }
  9. // 配置路由并使用中间件
  10. app.get('/',corsMiddleWare,(req,res)=>{
  11. res.send('hello!')
  12. })

4.3 単純なリクエストと複雑なリクエスト

CORS はリクエストを、①単純なリクエストと②複雑なリクエストの 2 つのカテゴリに分類します。

簡単なリクエスト

複雑なリクエスト

✅リクエストメソッド(メソッド)はGET、HEAD、POST

1 は、単純なリクエストまたは複雑なリクエストのいずれかです。
2 複雑なリクエストは、プリフライトリクエストを自動的に送信します。

✅リクエストヘッダーフィールドは以下に準拠する必要があります「CORSセキュリティ仕様」
簡単な注意: リクエスト ヘッダーが手動で変更されない限り、通常はこの仕様に準拠できます。

✅リクエストヘッダーのContent-Type値は以下の3つのみです。
●テキスト/プレーン
●マルチパート/フォームデータ
●application/x-www-form-urlencoded

プリフライトリクエストについて:

  • 1送信タイミング: プリフライトリクエストは実際のクロスドメインリクエストの前に送信され、ブラウザによって自動的に開始されます。
  • 2 メイン機能: 次のクロスドメインリクエストを許可するかどうかをサーバーに確認するために使用されます。
  • 3基本プロセス: まず、OPTIONS リクエストを開始します。事前チェックに合格した場合は、実際のクロスドメイン リクエストの開始を続けます。
  • 4 リクエスト ヘッダーの内容: OPTIONS プリフライト リクエストには通常、次のリクエスト ヘッダーが含まれます。

リクエストヘッダー

意味

起源

リクエストのソース

アクセス制御リクエストメソッド

実際にリクエストされたHTTPメソッド

アクセス制御リクエストヘッダー

実際のリクエストで使用されるカスタムヘッダー (存在する場合)

4.4CORS は複雑なクロスドメインリクエストを解決します

1 ステップ 1: サーバーは最初にブラウザのプリフライト要求を渡し、次の応答ヘッダーを返す必要があります。

応答ヘッダー

意味

アクセス制御許可オリジン

許可されたソース

アクセス制御許可メソッド

許可されたメソッド

アクセス制御許可ヘッダー

許可されるカスタムヘッダー

アクセス制御の最大有効期間

プリフライトリクエストの結果キャッシュ時間 (オプション)

画像.png

2 ステップ 2: 実際のクロスドメイン リクエストを処理する (単純なクロスドメイン リクエストを処理するのと同じ方法)

画像.png

サーバーコアコード:

  1. // 处理预检请求
  2. app.options('/students', (req, res) => {
  3. // 设置允许的跨域请求源
  4. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  5. // 设置允许的请求方法
  6. res.setHeader('Access-Control-Allow-Methods', 'GET')
  7. // 设置允许的请求头
  8. res.setHeader('Access-Control-Allow-Headers', 'school')
  9. // 设置预检请求的缓存时间(可选)
  10. res.setHeader('Access-Control-Max-Age', 7200)
  11. // 发送响应
  12. res.send()
  13. })
  14. // 处理实际请求
  15. app.get('/students', (req, res) => {
  16. // 设置允许的跨域请求源
  17. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  18. // 随便设置一个自定义响应头
  19. res.setHeader('abc',123)
  20. // 设置允许暴露给客户端的响应头
  21. res.setHeader('Access-Control-Expose-Headers', 'abc')
  22. // 打印请求日志
  23. console.log('有人请求/students了')
  24. // 发送响应数据
  25. res.send(students)
  26. })

4.5 cors ライブラリを使用して構成を迅速に完了する

上記の構成では、応答ヘッダーを自分で構成するか、または cors ライブラリを使用してミドルウェアを手動でカプセル化する必要があります。より簡単に構成を完了できます。

●corsのインストール

npm i cors

●シンプルな構成コルス

app.use(cors())

●corsを完全に設定する

  1. // cors中间件配置
  2. const corsOptions = {
  3. origin: 'http://127.0.0.1:5500', // 允许的源
  4. methods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], // 允许的方法
  5. allowedHeaders: ['school'], // 允许的自定义头
  6. exposedHeaders: ['abc'], // 要暴露的响应头
  7. optionsSuccessStatus: 200 // 预检请求成功的状态码
  8. };
  9. app.use(cors(corsOptions)); // 使用cors中间件

デフォルトでは、js はバックエンドによって設定された応答ヘッダーにアクセスできないため、バックエンドによって公開される必要があります。

5JSONP はクロスドメインの問題を解決します

1JSONP の概要: JSONP の使用法<script>标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持 CORS 的时,可以靠 JSONP 解决跨域。


2基本的なプロセス:

  • ○ステップ 1: クライアントが<script>标签,并将其src属性设置为包含跨域请求的 URL,同时准备一个回调函数,这个回调函数用于处理返回的数据。
  • ○ステップ 2: サーバーはリクエストを受信後、データをコールバック関数にカプセル化して返します。
  • ○ステップ 3: クライアントのコールバック関数が呼び出され、データがパラメータの形式でコールバック関数に渡されます。

3イラスト:

画像.png

4 つのコード例:

  1. <button onclick="getTeachers()">获取数据</button>
  2. <script type="text/javascript" >
  3. function callback(data){
  4. console.log(data)
  5. }
  6. function getTeachers(url){
  7. // 创建script元素
  8. const script = document.createElement('script')
  9. // 指定script的src属性
  10. script.src= 'http://127.0.0.1:8081/teachers'
  11. // 将script元素添加到body中触发脚本加载
  12. document.body.appendChild(script)
  13. // script标签加载完毕后移除该标签
  14. script.onload = ()=>{
  15. script.remove()
  16. }
  17. }
  18. </script>

5jQueryでカプセル化されたjsonp

?callback=?' は固定形式であり、自動的に解析されます。

  1. $.getJSON('http://127.0.0.1:8081/teachers?callback=?',(data)=>{
  2. console.log(data)
  3. })

6クロスドメインの問題を解決するためにプロキシを構成する

6.1 プロキシサーバーを自分で設定する

サーバー間でクロスドメインの問題は発生しません。サーバーとページが同じオリジンの下にあることを確認するには、express を使用して静的リソースを開始する必要があります。

  1. // 启动静态资源 让服务器跟页面同一个源
  2. app.use(express.static("./public"));

http-proxy-middleware を使用してプロキシを構成する

  1. const { createProxyMiddleware } = require('http-proxy-middleware');
  2. app.use('/api',createProxyMiddleware({
  3. target:'https://www.toutiao.com',
  4. changeOrigin:true,
  5. pathRewrite:{
  6. '^/api':''
  7. }

 

アドバンテージ:

  • 豊富な機能: http-proxy-middleware は、さまざまなプロキシのニーズを満たす豊富な構成オプションを提供します。
  • 複数のプロキシを柔軟に構成可能: 異なるインターフェイス パスに対応して、複数のプロキシ サーバーを構成できます。
  • リクエストをインターセプトできる: リクエストはカスタム処理関数を通じてインターセプトおよび変更できます。

欠点:

  • 設定は比較的複雑です。http-proxy-middleware ライブラリの設定ルールとパラメータを理解する必要があります。
  • 実稼働環境には適していません: http-proxy-middleware は主に開発環境で使用され、実稼働環境には適していません。

使用するシーン:

  • あらゆるビルドツールを使用するフロントエンドプロジェクトに適しており、あらゆる開発サーバーで動作します。
  • 複数のプロキシ サーバーを柔軟に構成する必要があるシナリオに適しています。
  • リクエストをインターセプトして変更する必要があるシナリオに適しています。

6.2 Nginx を使用してプロキシ サーバーを構築する

全体的なアイデアは、nginx に静的コンテンツ サーバーとプロキシ サーバーの両方の 2 つの役割を果たさせることです。

nginx の設定を次のように変更します。nginx のルート ディレクトリは C ドライブではないことが望ましいことに注意してください。

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. }
  6. # 配置代理
  7. location /dev/ {
  8. # 设置代理目标
  9. proxy_pass http://sph-h5-api.atguigu.cn/;
  10. }

2 フロントエンド プロジェクトを変更して、すべてのリクエストが /dev に転送されてから再パッケージ化されるようにします。

  1. const request = axios.create({
  2. baseURL:'/dev',
  3. timeout:10000
  4. })

次に、nginx サーバーに直接アクセスします。たとえば、nginx がポート 8099 で実行されている場合は、アクセスします。

http://localhost:8099

次に、リフレッシュ 404 問題が発生します。これを解決するには、nginx 構成を追加します。

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. try_files $uri $uri/ /index.html; # 解决刷新404
  6. }
  7. # 配置代理
  8. location /dev/ {
  9. # 设置代理目标
  10. proxy_pass http://sph-h5-api.atguigu.cn/;
  11. }

これら 2 つの「/」を追加すると、dev が削除されます

6.3 スキャフォールディングを利用してサーバーを構築する

1. vue.config.js ファイルを使用してプロキシを構成します。

Vue プロジェクトのルート ディレクトリに vue.config.js ファイルを作成し、次のコードを追加します。

  1. module.exports = {
  2. devServer: {
  3. proxy: {
  4. '/api': {
  5. target: 'http://api.example.com',
  6. changeOrigin: true,
  7. pathRewrite: {
  8. '^/api': ''
  9. }
  10. }
  11. }
  12. }
  13. }

上記のコードでは、devServerプロキシサーバーを設定するための設定項目です。でproxyプロパティはプロキシのルールを構成するために使用されます。/apiプロキシが必要なインターフェイス パスを示します。targetこの属性はプロキシのターゲット サーバー アドレスを表します。changeOriginこの属性は、リクエストの送信元アドレスを変更するかどうかを示します。pathRewrite要求されたパスをオーバーライドするために使用されるプロパティ。

アドバンテージ:

  • 簡単な構成: webpack-dev-server のプロキシ構成を使用すると、webpack 構成ファイルで簡単な構成を実行するだけで済みます。
  • 包括的な機能: webpack-dev-server は、ほとんどのプロキシのニーズを満たす豊富な構成オプションを提供します。
  • リクエストをインターセプトできる: リクエストはカスタム処理関数を通じてインターセプトおよび変更できます。

欠点:

  • サーバーを再起動する必要があります: 設定を変更した後、有効にするために webpack-dev-server を再起動する必要があります。
  • 実稼働環境には適していません: webpack-dev-server は主に開発環境で使用され、実稼働環境には適していません。

使用するシーン:

  • これは、webpack を使用して構築され、webpack-dev-server を通じて開発サーバーを起動するフロントエンド プロジェクトに適しています。
  • これは、単純なプロキシ構成が必要で、プロキシ構成を頻繁に変更する必要がないシナリオに適しています。