跨域?不存在的!JSONP带你“曲线救国” 😎

引言

各位前端小伙伴们,今天咱们来聊聊一个开发中让人头疼的老朋友------跨域 !😩 别怕,这次咱们不硬刚,要用一种"曲线救国"的方式来解决它!💪 没错,我说的就是 JSONP (JSON with Padding)!

为什么会有跨域这玩意?🤔

在开始我们的"救国"之路前,先来简单回顾一下为什么会有跨域这回事。

  • 安全第一!🔒: 想象一下,如果你随便打开一个网页,它就可以随意访问你浏览过的其他网站的信息,这得多可怕!😱 为了保护我们(前端)的隐私,浏览器就搞了个叫做 同源策略(Same-Origin Policy) 的机制。简单来说,同源策略 就是指浏览器只允许来自 相同源(Origin) 的 Web 应用之间进行资源共享。

  • 什么是 "同源"?🤔: 所谓 "同源" 就是指 协议(Protocol)+ 域名(Domain)+ 端口(Port) 这三者都相同,比如:

    • http://127.0.0.1:5502http://127.0.0.1:5502 是同源的。✅
    • http://127.0.0.1:5502https://127.0.0.1:5502 不是同源的。❌ (协议不同)
    • http://127.0.0.1:5502http://localhost:5502 不是同源的。❌ (域名不同,127.0.0.1localhost 虽然都指向本地,但浏览器会认为它们是不同的域名)
    • http://127.0.0.1:5502http://127.0.0.1:3000 不是同源的。❌ (端口不同)
  • 前端: 我们平时在浏览器里看到的页面,都是由 HTML、CSS 和 JavaScript 构成的。

  • 后端: 后端嘛,就是那些运行在服务器上的代码,通常用 Node.js、Java、Python 等来实现。

  • 前后端分离: 现在主流的前后端分离开发模式下,前端和后端通常运行在不同的服务器,因此跨域问题几乎是每天都要面对的!😩

CORS?No!JSONP走起!🏃‍♀️

面对跨域,通常我们首先会想到 CORS (Cross-Origin Resource Sharing) 跨域资源共享 。这是一种更标准的解决方法,需要后端配合设置 Access-Control-Allow-Origin 等响应头。 但是,如果我们后端暂时不支持 CORS 怎么办呢?别急!JSONP 闪亮登场!✨

JSONP 的核心思想:

就是利用 <script> 标签 的一个特性:script 标签的 src 属性不受同源策略的限制,可以跨域请求资源。

  • "曲线救国"的逻辑:

    1. 我们把要请求的数据,伪装成 JavaScript 代码
    2. 让浏览器用 script 标签去请求它。
    3. 浏览器会像执行 JavaScript 代码一样执行它,从而获得数据。

JSONP 是啥? 🤔

JSONP 全称是 JSON with Padding,中文名直译过来就是 "带填充的 JSON"。

  • "JSON" :还是我们熟悉的 JSON 数据,只不过它被"包裹"起来了。
  • "Padding" : 这里的 "Padding" 指的是在 JSON 数据外面加上 一个函数调用 ,像这样: callback({"name": "小明", "age": 18})

这样一来,浏览器会把服务器返回的 callback(JSON数据) 当成 JavaScript 代码执行,就能够成功获取数据啦!🥳

动手实践!写一个 JSONP 请求!👩‍💻

别光说不练!下面我们来实操一下,用 JS 封装一个 JSONP 请求函数,让你亲身体验一下 JSONP 的魔力!✨

步骤一:后端准备:

  • 首先,你要有一个 Node.js 环境。没有的话,快去官网下载一个:nodejs.org/
  • 运行下面的代码之前,记得在你的终端安装一下 nodemon,它可以帮你自动重启服务器,让你在开发时更加方便!😎 运行 npm install -g nodemon 安装吧!
  • 然后,在你的项目目录下,创建一个名为 server.js 的文件,把下面的代码粘进去:
javascript 复制代码
// server.js
const http = require('http')

const users = [
    {
        id: 1,
        name: 'zs'
    },
    {
        id: 2,
        name: 'ls'
    },
    {
        id: 3,
        name: 'ww'
    },
]
const server = http.createServer((req, res) => {
    res.end('callback(' + JSON.stringify(users) + ')')
})
server.listen(3000, () => {
    console.log('server is running at port 3000')
})
  • 记得在你的终端中运行 nodemon server.js 启动你的服务器!

    • 你的后端服务器就准备好啦! 😎 它会在 http://localhost:3000/ 返回一个包含用户信息的 JSONP 响应,别忘了!

步骤二:前端代码!

  1. 创建一个 index.html 文件,内容如下:

    html 复制代码
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
        <ul id="list">
    
        </ul>
        <script>
            let list = document.getElementById('list');
            let jsonp = (url, callback) => {
                let oScript = document.createElement('script');
                oScript.src = url;
                document.body.appendChild(oScript);
                window.callback = callback;
            }
            jsonp('http://localhost:3000/', (data) => {
                list.innerHTML = data.map(user => `
              <li>${user.name}
              </li>`).join('')
            });
        </script>
        <!-- <script src="http://localhost:3000/"></script> -->
        <!-- 
        小贴士:这里曾经尝试直接引入 <script src="http://localhost:3000/"> 来请
        求数据,但是发现它并没有按照我们的预期执行,这是因为直接引入并不会执行返回的代码
        ,所以最后我们还是采用动态添加 script 的方式 
        -->
    </body>
    
    </html>

    展示一下页面效果:

  1. 代码解释一下:

    • 我们首先获取页面上的 <ul> 标签,用于显示数据。

    • 我们定义了一个 jsonp 函数,它接受一个 url 和一个 callback 作为参数。

    • jsonp 函数内部:

      • 我们创建一个 <script> 标签,设置其 src 为传入的 url
      • 我们将 callback 函数赋值给 window.callback,这很重要!为什么?稍后会解释!
      • 我们把这个 <script> 标签添加到页面,发起请求。
    • 最后,我们调用 jsonp 函数,并传入请求地址和处理数据的回调函数。

步骤三:浏览器运行!

  • 用浏览器打开你的 index.html 文件,你应该能看到成功获取的数据,并且页面上展示了用户列表!🥳

你可能会好奇:

  • 为什么需要 window.callback

    • 这里用到了一个关键点:服务器返回的是 callback(JSON数据) 格式的 JS 代码。
    • 浏览器执行这段代码的时候需要找到全局的 callback 函数,才能正确调用它,并把数据传进去。所以,必须把回调函数挂载到 window 对象上,让它成为全局函数。
  • callback 可以换成其他名字吗?

    • 可以! callback 只是一个约定俗成的名字,你可以使用其他名字,比如 handleData

    • 但是,你要确保 前端和服务端使用相同的名字,即:

      1. 前端要定义: window.handleData = (data) => {...}
      2. 后端要返回:handleData(JSON数据)

JSONP 的限制 🤨

虽然 JSONP 很好用,但它也有一些局限性:

  1. 只支持 GET 请求: 因为 <script> 标签只能发起 GET 请求。
  2. 安全性问题: 由于 JSONP 实际上是执行服务器返回的 JavaScript 代码,如果服务器返回的脚本包含恶意代码,可能会导致安全问题。
  3. 处理错误困难: JSONP 请求的错误处理不如 XMLHttpRequest 和 fetch 方便。

总结 🎉

JSONP 是一种巧妙的跨域解决方案,它利用 <script> 标签的特性,通过"曲线救国"的方式实现了跨域数据请求。虽然有一些局限性,但在某些特定场景下,它仍然是一个很有用的技术。

希望这篇文章能帮助你更好地理解 JSONP 的原理和使用方法!如果你还有任何疑问,欢迎在评论区留言!我们一起学习,一起进步!💪

温馨提示:

别忘了下载全局 nodemon,它可以让你的开发更轻松!npm install -g nodemon 快去安装吧!

相关推荐
风月歌22 分钟前
基于Spring Boot的海滨体育馆管理系统的设计与实现
java·spring boot·后端
黄毛火烧雪下28 分钟前
React 深入学习理解
前端·学习·react.js
自不量力的A同学1 小时前
如何下载和安装Firefox 134.0?
前端·firefox
@_猿来如此2 小时前
Web网页制作之JavaScript的应用
前端·javascript·css·html·html5
小青柑-5 小时前
Go语言中的接收器(Receiver)详解
开发语言·后端·golang
顾尘眠6 小时前
http常用状态码(204,304, 404, 504,502)含义
前端
C++小厨神7 小时前
Bash语言的计算机基础
开发语言·后端·golang
BinaryBardC7 小时前
Bash语言的软件工程
开发语言·后端·golang
王先生技术栈8 小时前
思维导图,Android版本实现
java·前端
凡人的AI工具箱8 小时前
每天40分玩转Django:Django DevOps实践指南
运维·后端·python·django·devops