いくつかの一般的なnodejsドメイン間ソリューション

29762 ワード

ajaxを使用して前後のデータインタラクションを行う場合、ドメイン間でエラーメッセージが表示されることがよくあります.
Access to XMLHttpRequest at 'http://localhost:3000/cors' from origin 'null' has
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on 
the requested resource.

ドメイン間で生成される理由
これは、ブラウザの同源ポリシーのためです.これはブラウザの最も核心的で最も基本的なセキュリティ機能であり、あるドメインにロードされたスクリプトが別のドメインのドキュメント属性を取得または操作することを阻止します.(つまり,要求されたURLのドメインは現在のウェブページのドメインと同じでなければならない),同源ポリシーが欠けているとブラウザはXSS,CSFRなどの攻撃を受けやすい.
ドメイン間で発生する状況はどれですか?
  • ポートが異なる
  • プロトコルが異なる
  • ドメイン名が異なる
  • 同じURLとドメイン名に対応するIPが異なる//localhostと127.0.0.1はドメイン間
  • を生成します.
    まとめ:ポートが異なり、ドメイン名が異なり、プロトコルが異なるとドメイン間で表示されます.
    同源ポリシーは、次の動作を制限します.
  • Cookie、LocalStorage、IndexDBは
  • を読めません.
  • DOMとJSオブジェクトは
  • を取得できません.
  • AJAXリクエストは
  • 送信できません.
    ドメイン間での解決方法
    フロントエンド開発では、ドメイン間で問題が発生することは避けられません.以下、4つの方法を参照してください.
    注意:ドメイン間で一般的に発生するのは、前後の共通構成の解決である必要があります.
    方法1:サーバエージェント
    基本原理:サーバ間のリクエストにドメイン間の問題はありません.
  • まずフロントエンドが自分のサーバを要求する.サードパーティ製ミドルウェアcorsにより、フロントエンドと自分のサーバ間のドメイン間の問題を解決します.
  • 当方のサーバは、ターゲットサーバに対するサーバ要求の送信を開始します.
  • は、ネットワーク要求の結果をフロントエンド几种常见的nodejs跨域解决方案_第1张图片
  • に返す.
    フロントエンドコード:
    let  url ='http://localhost:3000/cors';//        
          $.get(url,(data)=>{
            console.log(data);//       
          })
    

    server.js:
    const cors = require('cors')
    const axios =require('axios')
    const express = require('express')
    const path = require('path')
    const app = express()
    //         cors        
    app.use(cors())//           ,               
    
    app.get('/cors',(req,res)=>{
      console.log('    ')
      let url ='http://ustbhuangyi.com/music/api/getDiscList?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8&notice=0&format=json&platform=yqq&hostUin=0&sin=0&ein=29&sortId=5&needNewCode=0&categoryId=10000000&rnd=0.2209329929181545'
      //            
      axios.get(url)
      .then((data)=>{
        // console.log(data.data)
        res.send(data.data)
      })
    })
    app.listen(3000,()=>{
      console.log('     ')
    })
    

    方法2:JSONP方式(フロントエンド常用)
    コア:scriptラベルのsrcプロパティにはドメイン間は存在せず、ファイル情報をロードできます.
    一般的にサードパーティインタフェースでは、サーバとクライアント間の通信の一般的な方法として使用できます.全プラットフォームブラウザでサポートされています.
    例えば、タオバオでお勧めのデータインタフェースに戻る必要があります.
    let url = https://suggest.taobao.com
    /sug?code=utf-8&q=%E8%A1%A3%E6%9C%8D&_ksTS=1577354356112_350
    &callback=taobao&k=1&area=c2c&bucketid=3//          ,   callback=        
    

    scriptラベルでドメイン間リクエストを実装し、jsonデータでコールバック関数を実行できます.
    <script>
         function taobao(data){
             console.log(data);
         }
    </script>
    

    このインタフェースで印刷されたデータは、下図に示す几种常见的nodejs跨域解决方案_第2张图片のように、プロジェクトがvueで書かれている場合は、jsonpというモジュールも使用できます.
    api.js
    import jsonp from 'jsonp'
    
    const getData = () => {
      let url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E8%A1%A3%E6%9C%8D&_ksTS=1577354356112_350'
      // param                        
      return new Promise((resolve, reject) => {
        jsonp(url,{param:'callback'},(err, data) => {
          if(err){
            reject(err)
          }else {
            resolve(data)
          }
        })
      })
    }
    

    index.vue
    import { getData} from "api/api.js";
    
    getData().then((res)=>{
    	console.log(res) //       ,    
    })
    

    この方法は簡単ですが、弊害もあります.
  • jsonpリクエスト方式はgetのみです.データを転送する過程で安全性がなく、転送できるデータの長さもかなり限られている.
  • インタフェースはjsonpフォーマットに合致する必要があります.そうしないと、この方法では意味がありません.

  • 方法3:cors設定要求の対応するヘッダフィールド
    CORSはW 3 C規格で、「ドメイン間リソース共有」(Cross-origin resource sharing)と呼ばれています.これにより、ブラウザがソース間サーバにXMLhttpRequest要求を発行することができ、AJAXがソースとしか使用できない制限を克服します.
    すべてのタイプのHTTPリクエストをサポートするが、ブラウザIE 10以下ではサポートされていない)、ajaxの各種ドメイン間リクエストに適している.
    バックエンドコード:
    var express = require('express');
    var app = express();
    
    //           
    function middleware(req, res, next) {
        console.log('      ')
        //     
        res.header("Access-Control-Allow-Origin", "*");//         ,*          
        res.header("Access-Control-Allow-Headers", "X-Requested-With");//   header  
        res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");//         
        res.header("X-Powered-By", ' 3.2.1');
        res.header("Content-Type", "application/json;charset=utf-8");
        next(); //        
    }
    
    //all             
    app.all(middleware) //          ,      
    
    app.get('/test', function (req, res) {
        res.send(req.query);
    })
    app.listen(3000, function () {
        console.log('     ');
    })
    

    postmanによるテスト結果を下図のように示します:几种常见的nodejs跨域解决方案_第3张图片
    方法四:WebSocket(H 5新機能)
    WebSocketはHTML 5の新しい通信プロトコルです.ブラウザとサーバのフルデュプレクス通信を実現し、ドメイン間通信を許可するserver push技術の良い実現です.
    オリジナルwebsocketには互換性の問題があり、簡単に使えますが、低バージョンのブラウザでは使えません.サードパーティ製ライブラリを使用できます.socket.ioは互換性の問題をよく解決し、使用方法も少し複雑です.
    フロントエンドコード:
    <body>
     <input type="text" id='msg' ><button onclick="send()">send</button>
    <script>
      //         
       var socket = io.connect('http://127.0.0.1:8081');
      //                  hehe        
       socket.on('hehe',(data)=>{
         console.log('        ',data)
       })
       function send(){
         let msg = document.getElementById('msg').value 
         //                    xixi       input value 
         socket.emit('xixi',msg)
       }
    </script>
    </body>
    

    server.js:
    var express = require('express')
    var app = express()
    //  socket     express      
    var server = require('http').Server(app);
    var io = require('socket.io')(server);
    
    io.on('connection',(client)=>{
       console.log('     ')
      //              hehe    123
       client.emit('hehe',123)
      //          xixi               
       client.on('xixi',(data)=>{
         console.log('        ',data)
       })
    })
    
    server.listen(8081,()=>{
      console.log('     ')
    });
    

    方法5:vue-cliのdevServerエージェント構成
    フロントエンドアプリケーションとバックエンドAPIサーバが同じホスト上で実行されていない場合は、開発環境でAPIリクエストをAPIサーバにエージェントする必要があります.この問題は、vue.config.jsのdevServer.proxyオプションで構成できます.vue cli: devServer.proxy
  • プロジェクトルートディレクトリの下にvue.config.jsファイル
  • を新規作成
  • module.exports内にdevServerを設定してエージェント
    module.exports={
      devServer:{
        proxy:{    //       
          //      
          '/hehe':{
            target:'http://www.target.com', //        
            changeOrigin:true,
            pathRewrite:{
              "^/hehe":''  //            
            }
          }
        }
      }
     }
    
  • を処理する
  • インタフェースを取得するネットワーク要求は、以前に設定した変更されたインタフェースの小さな暗号を使用して、ローカルサーバに要求を送信します.このときローカルサーバが受信アドレスは、/hehe/music/api/123であるため、ドメイン間
    import  axios from '../utils/axios'
    let url ='/hehe/music/api/123'
    axios.get(url)
    
  • は生成されない.
  • その後ローカルサーバを介してターゲットサーバに転送する、転送前にローカルサーバはtargetターゲットアドレス:target:'http://www.target.com'を受信アドレスurl前:url ='http://www.target.com/hehe/music/api/123'
  • に追加する.
  • このとき、送信する準備ができているアドレスと元のアドレスが一致していないことに気づき、hehe識別子が1つ増えました.pathRewriteが/heheをアドレスから
  • 削除する必要があります
    シーンの操作
    devServerによって設定されたエージェントは、ローカル環境でのみ使用できます.すなわち、エージェントによってリクエストがターゲットサーバに送信され、オンラインにパブリッシュされると、404パスが見つからないことを示すメッセージが表示されます.
    小結
    また、nginxエージェントのドメイン間、postMessageドメイン間、document.domain+iframe、location.hash+iframe、window.name+iframeなど、ドメイン間ソリューションもあります.
    最適ではありません.最適なのは、プロジェクトの実際のシーンと組み合わせて適切なドメイン間スキームを選択することだけです.