1. 什么是跨域
跨域指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。例如:AJAX 直接请求普通文件存在跨域无权限访问的问题
同源策略:
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现
简单理解:域名,协议,端口均相同则同源
2. 常用的跨域方式
1)设置请求头(以 Node.js 为例)
// 原生Node写法
require("http").createServer((req, res) => {
//设置允许跨域的域名,* 代表允许任意域名跨域
res.setHeader("Access-Control-Allow-Origin","*");
//跨域允许的请求方式
res.setHeader("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
res.end("end~~~~~");
}).listen(3000);
// express 写法
const express = require("express");
const app = express();
app.all("*",function(req,res,next){
res.header("Access-Control-Allow-Origin","*");
res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
next();
})
2)JSONP
JSONP 的产生
- 由于 AJAX 直接请求普通文件存在跨域无权限访问的问题,然而,凡是拥有
src
这个属性的标签都拥有跨域的能力,比如<script>
<img>
等 - 因此,想通过纯 Web 端,跨域访问数据就只有一种可能,那就是 Web 客户端用调用
JS
外部文件一样的方式,来调用跨域服务器上动态生成的JSON
格式文件 - 因为功能也是获取服务端数据,所以表面上看和 AJAX 比较像,但两者间的原理截然不同。
- 为了便于客户端使用数据,逐渐的形成了这种非正式传输协议 —— JSONP
JSONP 原理
- 用户传递一个
callback
参数给服务端,服务端返回数据时会将这个callback
参数作为函数名JSON
数据作为参数 返回给 Web 端,这样 Web 端就可以随意定制自己的函数来自动处理返回数据了。 JSONP
缺点只能使用GET发送请求,因为请求放在url
的?
后面 。
JSONP 实现
-
Web端
<script> function foo(data){ console.log(data); // {data: "JSONP数据"} } </script> <script src="http://localhost:3000/foo"></script>
-
服务端
require("http").createServer((req, res) => { if(req.url === "/foo" && req.method === "GET") res.end("foo({data:'JSONP数据'})"); }).listen(3000);
JSONP 封装成接口
-
Web端
// 原生接口封装 function addScript(src){ var script = document.createElement("script"); script.src = src; document.body.appendChild(script); } window.onload = function(){ addScript("http://localhost:3000/jsonp?callback=foo"); } function foo(data){ console.log(data); // {data: "JSONP数据"} } // JQuery 中的 JSONP 使用方法 (就是把上面的接口再封装) $.ajax({ type : "GET", url : "http://localhost:3000/jsonp", dataType : "jsonp", success : function(data){ console.log(data); // {data: "JSONP数据"} } })
-
服务端
const url = require("url"); const querystring = require("querystring"); require("http").createServer((req, res) => { let pathname = url.parse(req.url).pathname; let qs = querystring.parse(req.url.split("?")[1]); if(pathname === "/jsonp" && qs.callback) res.end(qs.callback + "({data:'JSONP数据'})"); }).listen(3000);