前言
众所周知,JavaScript在前端与后端均可运行,但是运行环境有所不同。
- 前端:现代浏览器(如 Chrome、Edge)中使用的是 V8 引擎来解析和执行 JavaScript 代码。
- 后端:使用封装了V8引擎的Node.js运行开发者在后端运行JavaScript代码。但是相比于前端其剥离了html,而专注于网络应用后端。
而 JSONP(JSON with Padding)作为 json 的一种"使用模式",在前后端的实现当然有所不同。
什么是 jsonp?
jsonp 并非编程语言亦或者一项技术,而更像是开发者遗留下来的bug,使得程序员可以利用这个bug来实现跨域。
jsonp (JSON with Padding) 是 JSON 的一种"使用模式",用于解决主流浏览器的跨域数据访问的问题,简单来说就是让网站从一个域到另一个域获取资源。其优缺点也很明显,兼容一些很老的浏览器,但是只能进行GET请求。
那为什么我们到不同的网站(域)访问数据要通过 jsonp 这种"模式"呢?因为浏览器自带一种安全机制----同源策略。
同源策略
同源策略是由 Netscape 提出的一个著名的安全策略,目前所有支持 JavaScript 的浏览器都会使用这个策略,它主要用于限制一个源的文档或脚本如何与另一个源的资源进行交互,来防止跨域攻击和数据泄露。
如果两个页面的域名、协议、端口都相同,则可以认为两个页面为同源,即:源(Origin) = 域名(Domain) + 端口(Port) + 协议(Protocol)。
- Protocol:用于访问资源的通信协议
- 例如:
http://
和https://
为不同协议
- 例如:
- Domain:域名是由一系列的子域名组成的,用于标识网站或服务器的位置
- 例如:
www.example.com
和api.example.com
,即使域名相同,但是子域名不同也视为不同源
- 例如:
- Port:端口是用于区分不同应用程序或服务的数字标识符
- 例如:
http://example.com:8080
和http://example.com
(8080 vs 默认80)
- 例如:
如果没有同源策略的限制,恶意网站可以通过 JavaScript 脚本读取用户在其他网站(比如银行网站)上登录后的敏感信息等,并将这些信息发送到攻击者的服务器。
当我们使用 AJAX 技术在网页和服务器之间发送或接收数据时,如果目标服务器和当前网页不是同源的,默认情况浏览器会阻止这种跨域请求。但是浏览器允许发起跨域请求,不过跨域请求返还的数据仍然会因为同源策略被浏览器拦截而无法被页面获取到。
jsonp 的使用
1.基于Node.js的服务端的JSONP格式
这里使用 node.js 早期的Commonjs模块化系统,在 ES6 模块化使用的是 import(例如:import http from 'http'
)
js
// 通过 require 方法 引入Node.js的内置'http'模块
const http = require('http');
// 创建数据模拟数据库
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]
// 创建http服务器
const server = http.createServer((req, res) => {
// 处理请求和响应
res.end("callback(" + JSON.stringify(users) + ")")
})
// 启动服务器
server.listen(3000, () => {
console.log('http服务在3000端口上启动了')
})
补充:
- http请求处理在 node.js 中通常是异步的,并且 node.js 有非堵塞性,可以使其能够高效处理高并发场景。(即:在同一时间内处理大量来自不同用户端的请求)
- 当一个 HTTP 请求发送到服务器时,与之绑定的回调函数将被执行。这个回调函数通常有两个参数:
req
和res
。req
(请求对象): 包含了所有关于请求的信息。res
(响应对象):使用res
对象构造并发送响应给客户端。
用户端的请求到达服务端的执行流程为:
rust
req(请求对象)接收请求后解析 -> 拿到资源 -> res(响应对象)返还响应 -> http连接结束
2.用户端发送请求
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");
// 定义 jsonp 函数
let jsonp = (url, callback) => {
let oScript = document.createElement('script');
oScript.src = url;
document.body.appendChild(oScript);
window.callback = callback;
}
// 调用 jsonp 函数,向服务器发起 JSONP 请求,并处理返回的数据
jsonp('http://localhost:3000/', (data) => {
list.innerHTML = data.map(user => `
<li>
${user.name}
</li>
`).join("");
})
</script>
</body>
</html>
解析:
- JSONP 的核心是利用
<script>
标签可以跨域加载资源的特性。 - 设置
<script>
标签的src
属性为目标 URL,这样浏览器会自动向目标 URL 发送请求,然后将将<script>
标签添加到页面的<body>
中,触发请求。最后通过callback
将服务器返还的数据传递给客户端。