跨域与前后端分离

Ken专注后端技术 2019-12-15

百度关于跨域的文章几乎每个文章都会有这么一个图和这几个解决方案

跨域与前后端分离

只要是跟当前页面所在url不同的请求都属于跨域请求,为什么我可以访问cdn或者引入其他网站的js或者css或者图片,那是因为src这个标签是支持跨域的,你用ajax去获取外网的js,css,图片试试,所以==把页面放在跟请求一个地址的服务器里面,就是最强的解决跨域的方案==

从jq-ajax文章过来的可以回去了,下面的内容超纲了

vue-cli是启动了一个开发版的本地服务器,域名是localhost:端口,在脚手架里写请求自然不可能,那就只能写完打包出来,把打包文件放到跟请求同一个域名的服务器里咯,这个虽然可以,但是也太傻了,改一下打包一下发布一下,还是看看其他解决跨域的方案吧

解决跨域方案

  1. 通过jsonp跨域(只能跨域get请求)
  2. document.domain + iframe跨域
  3. location.hash + iframe
  4. window.name + iframe跨域
  5. postMessage跨域
  6. 跨域资源共享(CORS)
  7. nginx代理跨域
  8. nodejs中间件代理跨域
  9. WebSocket协议跨域

上面的方案我们只取第六点,第7点,第八点,【7和8是一样的】

再看回axios篇里的这句代码

baseURL: process.env.NODE_ENV === 'development' ? '/proxy' : 'http://xxx.com',

需要解决的问题有

  • 线上正式版跨域调不通
  • 本地开发跨域调不通

线上正式版跨域调不通
首先就是要服务端支持跨域,叫做CORS,这个你要让后端去设置,如果是java和nodejs的开发,查看笔记有代码可以复制,开启CORShttp://xxx.com就支持跨域了,也就是打包完成后你放在http://aaa.com请求http://xxx.com的所有请求都可以了

本地开发跨域调不通
既然线上都开启CORS了,本地也可以开启CORS,然后把上面的代码改成

baseURL: process.env.NODE_ENV === 'development' ? 'http://localhost:后端的本地端口' : 'http://xxx.com',

行不行,个人测试不行,其实应该是可以的,但不知道什么原因,所以还是用上面的方法吧
既然浏览器不能跨域,就让本地服务器去请求后转给你,也就是让localhost:端口这个服务器去请求,上面的这个/proxy是简写,实际是localhost:端口/proxy,可以理解吧,为什么要加上这个值呢,这个值就是一个标识而且,改成aa,bb也行,这个值就是为了告诉脚手架服务器,你如果看到有请求带有这个标识,你就替我去另一个地址把请求数据拿过来

问题是我怎么让服务器有这个功能,vue-cli自带的有个proxy插件,配置一下就行
在vue.config.js里

devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
    proxy: {
      // 这个就是被监听的标识
      "/proxy": {
        // 然后脚手架去这个地址请求数据,这个就是本地的后端服务器以及端口
        target: "http://127.0.0.1:8080/",
        changeOrigin: true,
        pathRewrite: { '^/proxy': '' },
     }
   }
}

proxy的配置后很多,这个是最基础的写法,如果有其他需求,可以查一下百度

这时本地的脚手架应该就能调通本地的接口了,线上的项目也能调通线上的接口了,问题都解决了,就是一句baseURL的三元运算符和几行proxy的配置而已,本来不应该写这么多的,上代码自行理解就行,但是还是想解释一下,一解释就写了两篇笔记出来

谈谈前后端分离
这是一道面试题来的

前后端不分离
特点是:页面完全后后端模板生成,数据由后端渲染
比如node的ejs模板渲染
比如java的jstl和jsp渲染
这些写法需要专门去学,不是正常的html标签,如今已经都淘汰了,因为很少有人懂了,维护成本特别高

前后端半分离
就是把项目跟服务器放在同个服务器里,很常见的很普通的开发模式,jq时代

前后端分离
就是前端代码一个服务器,后端代码一个服务器,开启跨域支持,自己开发完更新自己的代码就行,但是前后端分离就失去了同源策略,如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击,可以查看无分类的《安全和攻击》笔记

补充jsonp
面试题来着,但正常不会用,以前豆瓣和百度的搜索接口就是用jsonp实现的
jsonp是怎么实现的,原理就是你把一个全局的==方法名==作为参数传给后端,比如参数叫cb,后端接口到参数后,查数据库然后把数据包在参数里,返回值如下,并且把返回值设置成js格式,数据返回后就会自动的执行全局的cb方法,这个方法的参数就是跨域的数据

cb('{"name":"name"}')

jq使用jsonp

$.ajax({
    type : "get",
    url : "http://xxxx",
    dataType: "jsonp",
    jsonp:"callback",
    jsonpCallback: "doo",
    success : function(data) {
        console.log(data);
    }
});

fetch和axios没有jsonp,需要自己封装

(function (window,document) {
    "use strict";
    var jsonp = function (url,data,callback) {

        // 1.将传入的data数据转化为url字符串形式
        // {id:1,name:'jack'} => id=1&name=jack
        var dataString = url.indexof('?') == -1? '?': '&';
        for(var key in data){
            dataString += key + '=' + data[key] + '&';
        };

        // 2 处理url中的回调函数
        // cbFuncName回调函数的名字 :my_json_cb_名字的前缀 + 随机数(把小数点去掉)
        var cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.','');
        dataString += 'callback=' + cbFuncName;

        // 3.创建一个script标签并插入到页面中
        var scriptEle = document.createElement('script');
        scriptEle.src = url + dataString;

        // 4.挂载回调函数
        window[cbFuncName] = function (data) {
            callback(data);
            // 处理完回调函数的数据之后,删除jsonp的script标签
            document.body.removeChild(scriptEle);
        }

        document.body.appendChild(scriptEle);
    }

    window.$jsonp = jsonp;

})(window,document)

补充WebSocket
WebSocket 是一种双向通信协议,也就是qq,微信的聊天原理,在建立连接之后,WebSocket的 server与 client都能主动向对方发送或接收数据而不受同源策略的限制。

function WebSocketTest(){
    if ("WebSocket" in window){
        alert("您的浏览器支持 WebSocket!");
        // 打开一个 web socket
        var ws = new WebSocket("ws://localhost:3000/abcd");
        ws.onopen = function(){
            // Web Socket 已连接上,使用 send() 方法发送数据
            ws.send("发送数据");
            alert("数据发送中...");
        };
        ws.onmessage = function (evt) {
            var received_msg = evt.data;
            alert("数据已接收...");
        };
        ws.onclose = function(){
            // 关闭 websocket
            alert("连接已关闭...");
        };
    } else{
        // 浏览器不支持 WebSocket
        alert("您的浏览器不支持 WebSocket!");
    }
}

相关推荐