JSONP 如何帮助我们解决跨域问题以及如何自己实现JSONP
什么是JSONP?
JSONP(JSON with Padding)是一种技术策略,其能够克服Web应用程序中的跨域数据访问限制。为了理解JSONP,我们需要先理解什么是跨域。
由于浏览器的同源策略,JavaScript只能获取和操作与其同源(即域名、协议和端口都相同)的数据。但在实际开发中,我们经常需要向不同的源请求数据,这就产生了跨域问题。
JSONP主要是通过动态 <script>
来进行跨域数据访问。在JavaScript中,<script>
标签的src属性不受同源策略的约束,因此我们可以通过src获取任何公开的资源。
JSONP是如何工作的?
- 定义一个函数,用以处理从服务器接收到的数据。
- 创建一个
<script>
标签,并将该函数名称作为callback参数值添加到请求URL中。 - 服务器端接收到请求后,将数据用这个函数进行包裹(也就是'padding'),然后返回。
- 浏览器执行返回的脚本,传入数据到我们预定义的函数中。
成熟JSONP工具使用示例
在现代JavaScript库(例如jQuery、Axios)中,已经内置了对JSONP的支持:
jsx// 使用 jQuery $.ajax({ url: '<http://example.com/data?callback=?'>, dataType: 'jsonp', success: function(data) { console.log(data); // 对数据进行处理 } }); // 或是使用 axios axios.jsonp('<http://example.com/data>', { params: { callback: 'handleData' } }).then(resp => { console.log(resp.data); // 对数据进行处理 });
自定义实现JSON方法
前端代码
bashfunction jsonp(url, params, callbackName) { // 将参数转换为url中的查询参数 let query = Object.keys(params) .map(k => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`) .join('&'); // 创建script标签 let script = document.createElement('script'); // 设置src属性值 script.src = `${url}?${query}&callback=${callbackName}`; // 插入到DOM中,发送请求 document.body.appendChild(script); } // 使用通用方法获取天气数据 jsonp( '<http://localhost:8080>', { city: 'Shanghai' }, 'handleWeatherData' ); // handleWeatherData 可以像之前一样定义 function handleWeatherData(data) { console.log(`The weather in ${data.city} is ${data.weather}.`); }
后端代码(使用 Node.js)
bashconst http = require('http'); const url = require('url'); http.createServer(function (req, res) { const queryObject = url.parse(req.url, true).query; const callback = queryObject.callback; // 删除callback和其他非业务相关的参数 delete queryObject.callback; // 假设响应的数据就是请求的所有参数 const responseData = JSON.stringify(queryObject); res.writeHead(200, {'Content-Type': 'application/javascript'}); res.end(`${callback}(${responseData})`); }).listen(8080);
JSONP的局限与安全问题
需要注意的是,JSONP只支持GET请求,不支持POST和其他类型的HTTP请求。并且由于其工作方式,JSONP存在一些重要的安全问题。因为所有的JSONP数据都是由 <script>
标签获取的,并且这些标签加载的内容会被浏览器立即执行,因此一个恶意的服务器可能会通过JSONP攻击你的网页。
JSONP的替代方案:CORS
浏览器和服务器都需要处理跨域问题的策略为Cross-Origin Resource Sharing(CORS)。与JSONP不同,CORS允许服务器对于特定的跨源请求进行更精细的控制,而不是像JSONP那样的全允许或全拒绝。
jsx// 使用axios进行CORS请求 axios({ method:'get', url:'<http://example.com/data>', headers: {'Access-Control-Allow-Origin': '*'} }).then(resp => { console.log(resp.data); // 对数据进行处理 });
尽管CORS与JSONP都能解决跨域问题,CORS提供了更丰富的错误处理方式和更安全的数据交互,因此,在对安全性和错误处理有所要求