JSONP CORS 与代理解决跨域

JSONP CORS 与代理解决跨域

一.背景

​ 在我们日常的工作开发中,经常遇到跨域问题,特别是前后端分离的开发模式下,跨域问题也是非常常见的.

二.为什么会出现跨域?

在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说 Web 是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

​ 它的核心就在于它认为自任何站点装载的信赖内容是不安全的。当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源。

​ 浏览器的同源策略,是对JavaScript实施的安全限制。

​ 所谓的同源是指,域名、协议、端口均为相同。

当前页面url 被请求页面url 是否跨域 原因
http://www.hello.com/ http://www.hello.com/a.html 同源(协议,域名,端口相同)
http://www.hello.com/ https://www.hello.com/a.html 跨域 协议不同(http/https)
http://www.hello.com/ http://sz.hello.com/ 跨域 子域名不同(www/sz)
http://www.hello.com:8080 http://www.hello.com:7070 跨域 端口号不同(8080/7070)
http://localhost:8080 http://127.0.0.1:8080 跨域 子域名不同(localhost/127.0.0.1)


在这里插入图片描述

三.解决跨域的方式

几种主流的跨域解决方案

JSONP处理跨域
1. 原理:

​ jsonp是一种跨域通信的手段,它的原理其实很简单:

​ a:首先是利用script标签的src属性来实现跨域。
b:通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客 户端通信。
​ c: 由于使用script标签的src属性,因此只支持get方法

2.实现方式:
//创建script标签
function createScript(){
    //定义一个script标签
   let oScript = document.createElement("script");
   //script的src属性 直接赋值为需要跨域的接口链接
   //并且定义callback参数,后面跟一个回调函数
  oScript.src = `https://api.asilu.com/today?callback=getTodays`;
       //将生成的script追加到我们的dom中
       document.body.appendChild(oScript);  
  }
	//callback对于的函数  
	function getTodays(data) {
        //获取跨域得到的对象数据
        let oTodays = data.data;
	}

​ 上述就是通过jsonp 实现了一个跨域请求,获取天气的数据.既然叫jsonp,显然目的还是json,而且是跨域获取,利用js创建一个script标签,把json的url赋给script的scr属性,把这个script插入到页面里,让浏览器去跨域获取资源,callback是页面存在的回调方法,参数就是想得到的json,回调方法要遵从服务端的约定一般是用 callback 或者 cb,特别注意的是jsonp只针对get形式的请求

3.优缺点

​ 优点:使用简便,没有兼容性问题。

​ 缺点:

​ 只支持 GET 请求。

​ 前后端需要配合。

​ 由于是从其它域中加载代码执行,因此如果其他域不安全,很可能会在响应中夹带一些恶意代码。

CORS跨域资源共享(xhr2)
1.原理

​ CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)- 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制- 整个CORS通信过程,都是浏览器自动完成,不需要用户参与- 对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样- 实现CORS通信的关键是服务端,只要服务端实现了CORS接口,就可以跨源通信

2.实现

​ 实现CORS并不难,只需服务端做一些设置即可:如

	// 控制允许的请求来源
	header("Access-Control-Allow-Origin:*"); // *表示允许任何来源 基本上设置这个就可以了
		
	//另外,还有一些需要设置put请求 delete请求的,还有自定义请求头,nodejs默认是get,post
    // 控制允许的自定义请求头
    'Access-Control-Allow-Headers': 'abc,efg',
    // 控制允许的请求方式
    'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE'

​ 注意:IE10以下不支持CORS

3.优缺点

​ 优点:

​ CORS 通信与同源的 AJAX 通信没有差别,代码完全一样,容易维护。

​ 支持所有类型的 HTTP 请求。

缺点

​ 存在兼容性问题,特别是 IE10 以下的浏览器。

​ 第一次发送非简单请求时会多一次请求。

服务器代理跨域
1.原理:

​ 通过服务端语言代理请求。如PHP,C# 服务端语言是没有跨域限制的。- 让服务器去别的网站获取内容然后返回页面。因为同源策略是针对浏览器的安全性限制.服务器不存在跨域问题,所以可以由服务器请求所要域的资源再返回给客户端。

​ 我们在请求第三方的数据时,通过浏览器的ajax请求肯定是不行的,因为人家也不会给你设置cors,所以我们这边的服务器代理解决跨域的方式就应运而生了.

2.实现

我这边通过nodejs+express实现服务代理跨域

需要安装中间件 http-proxy-middleware

$ npm install http-proxy-middleware

在这里插入图片描述

服务端代码

// 通过代理解决跨域问题

/**
 * 使用nodejs启动一个代理服务
 * 第三方的  http-proxy-middleware 中间件
 */

//引入express
const express = require('express');
//引入代理中间件
const { createProxyMiddleware } = require('http-proxy-middleware');
//声明express实例
const app = express();

//  注册一个cors的中间件,允许跨域
app.use((req, res, next) => {

    res.set({
        //允许所有域请求,实际开发中,*需要改成对应的域名
        'Access-Control-Allow-Origin': '*',
        // 设置允许前端传递的那些自定义请求头
        'Access-Control-Allow-Headers': 'token',
        // 设置允许的请求方式
        'Access-Control-Allow-Methods': 'GET,POST,PUT,PATCH,DELETE'
    });
	//必须要写,将控制权交给下一个
    next();
});

// 注册一个代理中间件
// 前端服务:http://localhost:8080
// 代理服务:http://localhost:3000
// 目标服务:http://m.maoyan.com

app.use('/api', createProxyMiddleware({
    //配置选项
    // 目标地址:只需要协议和主机
    target: "http://m.maoyan.com",
   
   /**
   * 路径重写
   * 
   * 当我们通过代理访问目标接口的流程大致如下
   * http://localhost:8080 -> 请求 -> 
   * http://localhost:3000/api/ajax/movieOnInfoList -> 代理到 -> 
   * http://m.maoyan.com/api/ajax/movieOnInfoList
   * 这时真实的目标接口地址是没有 /api 这个前缀的。所以会导致请求失败 404 等问题
   * 
   * 设置如下的路径重写规则之后,流程如下
   * http://localhost:8080 -> 请求 -> 
   * http://localhost:3000/api/ajax/movieOnInfoList -> 代理到 -> 
   * http://m.maoyan.com/ajax/movieOnInfoList
   */
    pathRewrite: {
        "^/api": ""
    },
    // 虚拟托管站点所需, 一般直接设置为true就好
    changeOrigin: true
}));

//监听3000端口,启动服务
app.listen(3000, () => {
    console.log("代理服务启动成功");
});

前端代码

 <script>
    $(function () {
      $.ajax({
        url: 'http://localhost:3000/api/ajax/movieOnInfoList',
        type: 'GET',
        success: function (res) {
          console.log(res)
        }
      })
    })
  </script>

上面是3中主流的跨域解决方案,还有其他的解决方式,有兴趣可以大家去研究:JSONP、CORS、服务器代理、document.domain、window.name、location.hash、postMessage ,nginx代理跨域

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/105210065
今日推荐