热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【小哥哥,跨域要不要了解下】JSONP

ps:为了保证前后端编码的一致性,本系列文章中涉及部分后端内容.后端统一使用原生nodejs来搞,请

打算纯前端做一个接口测试工具, 直到遇到

【小哥哥, 跨域要不要了解下】JSONP

这个报错, 触碰到了知识盲区了, 怎么办???

【小哥哥, 跨域要不要了解下】JSONP

还好, 有谷哥和度娘. 原来是跨域 随手整理了一下常用的跨域方式处理方案, 这里马上分享给大家 :yum:

ps: 为了保证前后端编码的一致性, 本系列文章中涉及部分后端内容. 后端统一使用原生 nodejs 来搞, 请奔走相告.

准备工作

为了托管我们的静态页面, 我们需要一个可以提供服务器环境的插件, 这里推荐 live-server , 通过命令 npm i -g live-server 安装即可. 该插件支持html文件热更新. 那用户体验简直飞起. 一键启动, 只需要在需要托管的目录执行 live-server . 即可.

【小哥哥, 跨域要不要了解下】JSONP

ps: live-server 依赖 nodejs, 没有安装的小伙伴, 请参照这篇文章安装 nodejs.

AJAX 访问接口跨域解决方案

首先, 更正几个常见的错误认识:

  1. 同源策略是浏览器的行为, 和 js 关系不大.
  2. 所谓跨域是指请求发起方页面所在的 url 与访问的 api 存在协议, 域名, 端口中任意一个不同即视为跨域. 并不单单是指域名.
  3. 跨域这个东西, 日常工作中并不是很常用. 你想, 谁会闲的没事儿干总是请求人家别人的 api 去.

jsonp

可能有小伙伴会说. 圈圈, 你扯淡, 既然浏览器有跨域限制. 为什么我司项目从bootcdn, 引入的 jquery 依然跑在信息高速路上, 没有任何低头的意思?

hhh, :smile:. 这个质疑提的好. 浏览器同源策略禁止的是 ajax 请求. 然鹅, jquery 是一个 js 文件. 不受该策略的限制.

我尼玛, 那到底是啥限制啥不限制嘛???

【小哥哥, 跨域要不要了解下】JSONP

根据MDN (自备梯子), 对于浏览器的同源策略的解释, 不受限制的外域资源加载情况有以下几种:

  • script
  • link
  • img
  • video
  • object embed applet
  • font-face 有的浏览器允许, 有的禁止
  • frame

那么问题来了, 挖掘机学校..., 不好意思走错片场了. 既然有这么多方式可以绕过浏览器同源策略的限制. 那么, 是不是我们可以做一点事情呢 ^_^

答: 是的 :smile:.

那还不抓紧搞起来?

【小哥哥, 跨域要不要了解下】JSONP

我们使用第一个特例 script 一步一步实现跨域访问 (jsonp).

  • 首先, 创建本次文章的项目目录
    【小哥哥, 跨域要不要了解下】JSONP
    目录中, be 代表是后端项目, fe 代表前端项目. jsonp 目录说明我们是用 jsonp 的方式实现跨域.
  • 在项目根目录下执行 live-server ./fe/jsonp/ 启动前端 web 容器
  • 编辑 ./fe/jsonp/ 目录下的 index.html 文件. 代码如下:


    
    
    
    


    

jsonp 实现跨域

  • 浏览器访问localhost:8080浏览器如下图说明前端 web 容器部署成功.

    【小哥哥, 跨域要不要了解下】JSONP
  • 编写后端代码, 编写 be/jsonp/index.js 文件, 文件内容如下

var http = require('http');
var PORT = 8888

// 创建一个 http 服务
var server = http.createServer(function(request, response) {
    response.end('hello world')
})

// 启动服务, 监听端口
server.listen(PORT, function() {
    console.log('服务启动成功, 正在监听: ', PORT)
})
  • 编写完成后命令行执行 node ./be/jsonp/index.js 命令行中出现

    【小哥哥, 跨域要不要了解下】JSONP
    说明后端程序启动成功.此时可以通过浏览器访问localhost:8888获得 hello world
    【小哥哥, 跨域要不要了解下】JSONP
  • 下来, 我们在前端的 index.html 中尝试通过 ajax 请求 http://localhost:8888/ 来获取返回数据, 添加如下代码, 添加以后 代码

 
 

回到浏览器, 查看页面控制台, 熟悉的错误出现了. Access to XMLHttpRequest at http://localhost:8888/ from origin http://127.0.0.1:8080 has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 这个错误说明了, 我们是不能通过 ajax 的方式从 http://127.0.0.1:8080 访问 http://localhost:8888/ 的.

既然不能通过 ajax 实现跨域的访问, 同时 mdn 又说 script 标签不受同源策略的限制. 那么, 我们尝试一下用 script 标签引入 http://localhost:8888/ 试试?

【小哥哥, 跨域要不要了解下】JSONP

此时的 代码 , 网络请求没有问题. 知识报了 js 文件不合法的问题. 如果我们把接口返回的数据调整为规范的 js 是不是, 嗯哼???

干起, 修改后端代码, 返回的内容由 hello world 改为 console.log('hello world') , 修改后的 代码 (修改完后端代码以后切记重启服务哈 ^_^)

不得了, 不得了, 返回的结果不紧没有报错, 甚至可以执行. 我们从后端返回的 hellow world 成功的答应到了控制台了.

【小哥哥, 跨域要不要了解下】JSONP

试想一下, 如果我们通过 js 文件里定义一个变量用于存放后端返回给前端的数据, 前端插入一个 script 标签, 把后端返回的变量定义执行一把. 那样定义的变量岂不是就可以在全局可以获取到后端定义的变量了. 赶紧试一把 :smile:

首先修改后端代码, 只需要调整一行.(修改完后端代码以后切记重启服务哈 ^_^)

response.end("var aaaa = {name: 'quanquan', friend: 'guiling'}");

其次调整前端代码


当前 代码 , 通过这种方式, 我们能够成功的获取到后端返回的数据. 但是, 接口这个东西时快时慢. 写个定时器轮询? 有点不够 666, 肿么办?

【小哥哥, 跨域要不要了解下】JSONP

======================== 思考 5 分钟 ========================

【小哥哥, 跨域要不要了解下】JSONP

======================== 5 分钟已过 ========================

既然, 写在 script 标签上的内容是可以直接执行的. 那么, 如果我们把变量的定义改写成一个函数的执行可不可以呢 ^_^, 试试?

后端(修改完后端代码以后切记重启服务哈 ^_^)

response.end("aaaa({name: 'quanquan', friend: 'guiling'})");

前端


结果

【小哥哥, 跨域要不要了解下】JSONP

此时 代码 , 目前为止, 我们已经彻底解决了跨域的问题. 很靠谱有木有? 当然木有. 这个玩意儿只是说明了 jsonp 的原理, 并没有实用性. 下一步, 我们做一点封装. 让我们的代码更健壮 :muscle|type_1_2:

最后, 修改一把代码

前端

// 创建 Jsonp 类
// 初始化时传入两个参数, url 是接口的url
// cb 是对于接口返回的参数的处理
function Jsonp(url, cb) {
    this.callbackName = 'jsonp_' + Date.now()
    this.cb = cb
    this.url = url
    this.init()
}

// 初始化方法 用于拼接 url
Jsonp.prototype.init = function() {
    if(~this.url.indexOf('?')) {
        this.url = this.url + '&callback=' + this.callbackName
    } else {
        this.url = this.url + '?callback=' + this.callbackName
    }
    this.createCallback()
    this.createScript()
}

// 创建 script 标签, src 取接口请求的url
Jsonp.prototype.createScript = function() {
    var script = document.createElement('script')
    script.src = this.url
    script.Onload= function() {
        this.remove()
    }
    document.body.appendChild(script)
}

// 绑定回调函数
Jsonp.prototype.createCallback = function() {
    window[this.callbackName] = this.cb
}

// 创建 jsonp 实例, 并指定回调函数
new Jsonp('http://localhost:8888/', function(data) {
    console.log(data)
})

后端(修改完后端代码以后切记重启服务哈 ^_^)

const http = require('http');
// 新引入了 url 模块, 主要用于解析请求参数
const url = require('url');

const PORT = 8888;

// 创建一个 http 服务
const server = http.createServer((request, response) => {
  // 获取前端请求数据
  const queryObj = url.parse(request.url, true).query;
  // 这里把前端传来的 callback 字段作为后端返回的回调函数的函数名称
  response.end(`${queryObj.callback}({name: 'quanquan', friend: 'guiling'})`);
});

// 启动服务, 监听端口
server.listen(PORT, () => {
  console.log('服务启动成功, 正在监听: ', PORT);
});

目前 代码 , 至此我们已经能够顺利的获取跨域资源了. :clap|type_1_2:.

下集预告: jsonp 是一种传统的跨域解决方案, 关于这种方式的优缺点, 请度娘, 下一节, 我们一起学习相对比较现代一点的跨域解决方案. CORS , See You


以上所述就是小编给大家介绍的《【小哥哥, 跨域要不要了解下】JSONP》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 我们 的支持!


推荐阅读
  • React 小白初入门
    推荐学习:React官方文档:https:react.docschina.orgReact菜鸟教程:https:www.runoob.c ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • 本文介绍了JavaScript进化到TypeScript的历史和背景,解释了TypeScript相对于JavaScript的优势和特点。作者分享了自己对TypeScript的观察和认识,并提到了在项目开发中使用TypeScript的好处。最后,作者表示对TypeScript进行尝试和探索的态度。 ... [详细]
  • loader资源模块加载器webpack资源模块加载webpack内部(内部loader)默认只会处理javascript文件,也就是说它会把打包过程中所有遇到的 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 前言:原本纠结于Web模板,选了Handlebars。后来发现页面都是弱逻辑的,不支持复杂逻辑表达式。几乎要放弃之际,想起了Javascript中ev ... [详细]
  • document .ready中的函数怎么被按钮调用? ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 1.移除consol.log()的babel插件安装:npmibabel-plugin-transform-remove-console-D配置:babel.config.js:这 ... [详细]
  • ReactJSUIAnt设计空组件原文:https://w ... [详细]
  • npminstall-Dbabelcorebabelpreset-envbabelplugin-transform-runtimebabelpolyfillbabel-loader ... [详细]
author-avatar
圈闭仔笨仔
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有