jsonp 和 CORS 处理跨域

92 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

什么是跨域

当一个请求的url的协议/端口/域名三者之间任意一个与当前页面的url不同就是跨域

image.png

什么是同源策略

同源策略/SOP(same origin pllicy)是浏览器最核心的的安全策略,如果没有同源策略,浏览器很容易受到xss/csfr等攻击,同源策略有效的阻止了非法的跨域之间的数据通讯

同源策略策略是浏览器的安全策略,所有如果通讯不包含浏览器器就没有这个问题。

跨域问题虽然在前端产生,但是前端无法在没有后端支持的情况下解决跨域问题,每个面试官总喜欢问跨域问题,心里真是很郁闷,你能独立解决跨域吗?希望前端面试不要再问这个问题了,建议后端面试时,问一下跨域解决方法,因为在工作中,不止一次遇到跨域问题,大多数的后端都不知道怎么处理,甚至有的要我把允许跨域的响应头发给他,就差替他写了,虽然我也是在面试官频频问的情况下,迫不得已的学习的

html 特殊标签

link script img frame 这些标签具有跨域特性,可以直接访问,不受同源策略策略约束 Jsonp(JSON with Padding) 利用这一点实现的一个跨域,利用script标签发送请求,请求返回一段js代码,就可以在本地执行了。把数据填充到参数中,就可以在客户端函数的参数中获取到数据 举例 服务器端,利用node.js node.js脚本启动一个服务,监听端口3000,当有人访问http://localhost:3000/jsop 时,返回一个字符串'getJSON({"name":"tom","age":19})',客户端script加载到本地后,就当成json执行,然后本地刚好一个getJOSN函数,就执行这个函数就行了

创建文件 ./server.js ,命令行执行node ./server.js 或者 nodemon ./server.js

const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
    const {
        url
    } = req;
    let data = null;
    switch (url) {
        case '/data':
            // 同步读取data.json内容
            data = fs.readFileSync('./data.json')
            break;
        case "/jsonp":
            // 同步读取data.json内容
            let json = fs.readFileSync('./data.json')
            // 返回数据是一个字符串,js代码 getJSON({"name":"tom","age":19})
            data = "getJSON(" + json + ")"
            break;
    }
    res.end(data);
})
server.listen('3000', () => {
    console.log('http://localhost:3000')
})

再创建一个data.json文件

{
    "name":"tom",
    "age":19
}

客户端

首先定义一个函数getJSON(举例叫这个,随便叫),随后在后面利用script向服务器发送一个请求 用live-server打开这个html http://127.0.0.1:5500/demo1/index.html ,这个路径根据自己真实情况决定,总之和http://localhost:3000/jsop 肯定是不同域 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body></body>

  <!-- jsonp 开始 -->
  <script>
    function getJSON(res) {
      console.log(res);
    }
  </script>
  <script src="http://localhost:3000/jsonp"></script>
  <!--  jsonp 结束 -->


</html>


正经的jsonp,不是这种约定函数名的方式实现的,会在url后面拼接?callback=xxx,后端根据这个参数得到函数名,然后返回正确的拼接好的函数调用的字符串, 缺点:只支持get,不支持其他请求方法,不优雅,不正规

CORS

只要服务器端设置 Access-Control-Allow-Origin就可以了,前端无需设置。 现在一般都是用CORS解决跨域,方便快捷,浏览器觉得总有些服务器不怕被攻击,你都不怕,我怕啥,管那个呢,只要你跟我说你来者不惧或者指定的url允许请求你的数据,我就不拦截了 在没解决之前,看看跨域的效果 不解决的效果如下,浏览器控制台中network里面 fetch/Xhr里,状态显示 CORS错误 这个/data ,在开始node.js代码里已经处理了,服务器代码暂时不用改,期望返回一个json,但是实际上服务器也返回了json,但是被浏览器拒绝了。

  ...
  <!--  jsonp 结束 -->
  
  <script>
    fetch("http://localhost:3000/data")
      .then((response) => response.json())
      .then((res) => {
        console.log(res);
      });
  </script>

image.png

解决方法 在服务器端配置一下响应头,就ok了,无需前端做任何处理 配置res.setHeader("Access-Control-Allow-Origin", "*"),来者不惧,真的对任何的url都开放,随便调, 配置res.setHeader("Access-Control-Allow-Origin", ['http://127.0.0.1:5500']),只有配置的域名才能访问


   ...
   case '/data':
            data = fs.readFileSync('./data.json');
            res.setHeader("Access-Control-Allow-Origin", "*")
            // 或者
            // res.setHeader("Access-Control-Allow-Origin", ['http://127.0.0.1:5500'])
            break;
   ...

image.png

image.png