• 前端跨域常见的处理方法


    1、 浏览器的同源策略:协议+域名+端口 都相同才叫同源,有一个不同就会产生跨域

    JsonP cors postMessage document.domain window.name lacation.hash http-proxy nginx websocket

    对于link,script,img是不受同源策略限制的,jsonp的原理 就是通过script不受同源策略限制而现实的。 通过src发送一个请求,如百度搜索的实现就是通过jsonp实现的 具体实现方法:
    let script = document.createElement("script"); 
    script.src="https://www.baidu.com/sugrec?prod=pc&wd=dd&cb=show";
    document.body.appendChild(script);

    上面是去调用百度的jsonp,传入搜索字符串dd,回调函数show,它会返回一个show()包裹的结果对象 所以我们定义show方法,就可以拿到返回值

    function show(data){ console.log(data) }
    

    上面的方法实现了通过jsonp的方式跨域,但是写起来相对繁琐,我们将其封装一下,通过下面的方法直接获取

    jsonp({ 
      url:"https://www.baidu.com/sugrec", 
      params:{prod="pc",wd="dd"}, 
      cb:"show" 
    }).then(data=>{ console.log(data) })
    
    接下来定义一个jsonp方法
    function jsonp({url, params, cb}){ 
      return new Promise((resolve,reject)=>{
        params = {...params,cb};
        let script = document.createElement("script");
        let paramArr = [];
        for(let key in params){
          paramArr.push(`${key}=${params[key]}`);
        }
        window[cb] = function(data){
          resolve(data);
          document.body.removeChild(script);
        }
        script.src=`${url}?paramArr.join("&")`;
        document.body.appendChild(script);
      })
    }
    通过cors实现跨域,这个主要需要靠服务端支持,设置各种头信息 主要头信息有:
    Access-Control-Allow-Origin 这个需要配置白名单,允许跨域的地址 Access-Control-Allow-Methods 允许访问的方法,默认支持get和post Access-Contro-Allow-Headers 允许客户端发送指定头信息 Access-Control-Allow-Credentials 允许客户端发送cookie Access-Control-Allow-Max-Age 每次发送请求的时候,都会先发送一个options请求去预检当前服务器是否允许当前请求方式,max-age设置就是设置在多少秒内不要再发送预检请求 Access-Control-Expose-Headers 允许服务端可以向客户端发送某些响应头信息,且客户端可以获取到该头信息
    具体使用方法(我们用express模拟两个不同端口的服务地址):
    定义1.server.js文件
    let express = require("express"); 
    let app = new express(); 
    app.use(express.static(__dirname));
    
    app.listen(3000);
    

    再定义2.server.js文件:

    let express=require("express"); 
    let app = new express(); 
    app.listen(4000)
    这样我们可以分别启动两个服务localhost:3000 和localhost:4000 然后在同级目录下定义a.html页面:
    let xhr = new XMLHttpRequest(); 
    xhr.open("GET","http://localhost:4000/getData");
    xhr.onreadystatechange = function(){
      if(xhr.readyState==4){
        if(xhr.status>=200 && xhr.status<300 || xhr.status==304){       console.log(xhr.response)
        }
      } }
    xhr.send();
     上面的html中,我们向4000端口的地址发送了ajax请求,然后在浏览器中打开localhost:3000/a.html,会报跨域问题,
     解决方式,就是在2.server.js中,添加上面的Access-Control-Allow-Origin,
    具体实现如下: 定义一个白名单
    let whiteLists=["http://localhost:3000"];
    定义一个中间件
    app.use(function(req,res,next){ 
      let origin = req.headers.origin;
      if(whiteList.includes(origin)){
        res.setHeader("Access-Control-Allow-Origin", origin);
      }
    })
    如果我们希望除了get post,还支持put delete等方法,在上面的配置下面,添加如下header
    res.setHeader("Access-Control-Allow-Methods","PUT,DELETE");
    如果我们希望客户端可以向服务端发送cookie,配置如下:
    res.setHeader("Access-Control-Allow-Credentiala",true)
    如果希望客户端向服务端发送指定头信息,配置入下:
    res.setHeader("Access-Control-Allow-Headers","name");// name是指定头信息的名字
    服务端希望向客户端发送响应头:
    res.setHeader("Access-Control-Expose-Headers","cookie");
    完整代码入下:
    1.server.js
    let express = require("express"); 
    let app = express();
    app.use(express.static(__dirname)); // 设置当前路径为静态文件路径
    app.listen(3000);
    2.server.js
    let express = require("express");
    let app = new express();
    // 服务端解决跨域,需要配置白名单
    let whiteLists = ["http://localhost:3000"];
    
    app.use(function(req,res,next){
        let origin = req.headers.origin;
        if(whiteLists.includes(origin)){
            res.setHeader("Access-Control-Allow-Origin",origin);
            res.setHeader("Access-Control-Allow-Headers","name");   // 这里允许设置多个headers,用逗号隔开即可
            res.setHeader("Access-Control-Allow-Credentials",true); // 允许客户端发送头信息
            res.setHeader("Access-Control-Allow-Methods","PUT"); // 默认支持get和post。如果要支持其他方法,需要设置头信息
            // 可以设置options预检请求的有效期,即5秒内不再发出
            res.setHeader("Access-Control-Allow-Max-Age",5);
            res.setHeader("Access-Control-Expose-Headers","cookie"); // 设置服务端允许返回的响应头信息,且客户端可以读取
            if(req.method=="options"){ // 如果请求是options预检,直接返回
                res.end();
            }
        }
        // 一定要调用next(),否则下面的方法不会执行
        next();
    })
    app.post("/getData",function(req,res){
        res.end("post 已经收到了")
    })
    app.put("/getData",function(req,res){
        res.setHeader("cookie","this is server cookie"); // 服务端设置响应头,客户端想要获取,需要设置Access-Control-Expose-Headers
        res.end("这个是PUT方法")
    })
    app.get("/getData",function(req,res){
        console.log(req.headers,"====");
        res.end("我不爱你");
    })
    
    app.listen("4000");
    

    a.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>CORS处理跨域</title>
    </head>
    <body>
        Hello
        <script>
            let xhr = new XMLHttpRequest();
            // 向localhost4000发送请求 默认express支持get和post请求,
            // 如果要修改成其他请求方法 如put delete等,需要服务端设置Allow-Methods头信息
            // xhr.open("GET","http://localhost:4000/getData");
            xhr.open("GET","http://localhost:4000/getData");
            xhr.setRequestHeader("name","fiona");   // 前端设置Header,需要服务端配置Access-Control-Allow-Headers
            // 前端设置cookie, 必须设置withCredentials, 并且要求服务端设置allow credentials头
            document.cookie = "name=fionazhong";
            xhr.withCredentials = true;
            xhr.onreadystatechange = function(){
                if(xhr.readyState==4){
                    if(xhr.status>=200 && xhr.status<300 || xhr.status==304){
                        console.log(xhr.response);
                        console.log(xhr.getAllResponseHeaders("cookie"))
                    }
                }
            }
            xhr.send(); 
        </script>
    </body>
    </html>
    
    我们为了实现某些效果,经常会在页面嵌套iframe,那么iframe外面和里面如何通信呢?可以使用下面说的postMessage方法  
  • 相关阅读:
    javaweb中带标签体的自定义标签
    javaweb带父标签的自定义标签
    Filter的常见应用
    Filter内容
    JFace TableViewer性能改善 -- 使用VirtualTable
    SWT table性能改善 -- 使用VirtualTable
    java自动探测文件的字符编码
    [小技巧]Filezilla无法确定拖放操作目标,由于shell未正确安装__解决办法
    批量导出VBA工程中的Source
    开源许可证知多少
  • 原文地址:https://www.cnblogs.com/fiona-zhong/p/14015723.html
Copyright © 2020-2023  润新知