跨域访问是指在浏览器中向不同源的服务器请求数据时出现的安全限制。为了在深度讨论 AJAX 的跨域访问之前,需要先了解一下同源策略。
同源策略
同源策略是由 Netscape 提出的一个重要的安全策略。当一个浏览器创建一个Web页面的时候,它会创建一个域,这个域通常是页面的 URL(Domain)。
同源策略触发的条件包括以下三方面:
- 协议相同
- 域名相同
- 端口相同
比如,http://www.example.com/page1.html
和 http://www.example.com/page2.html
属于同一个域,而 http://www.example.com:8080/page1.html
和 http://www.example.com/page1.html
不属于同一个域。
同源策略不允许跨域获取网页中的数据,发起异步请求来获取数据。AJAX 是异步请求的一种方式,所以在同一个域中使用 AJAX 不会有问题。但是如果我们需要从不同的域请求数据,那么 AJAX 就会遇到跨域问题。
跨域访问
跨域访问是指在浏览器中向不同源的服务器请求数据时出现的安全限制。遇到跨域访问时,浏览器会发出提示警告,拒绝向其他域提交信息并获取返回的数据。
例如,一个页面在访问http://192.168.1.10:8080/data.json
获取数据时,就会被浏览器拒绝,因为它的域并不是http://192.168.1.10
。
解决方案
出于安全考虑,浏览器不允许跨域访问数据,但我们仍可以通过以下几个方案来解决跨域问题:
- JSONP
- CORS
- 代理
JSONP
JSONP(JSON with Padding)是一种跨域请求数据的方法,原理是在页面中创建一个 <script>
元素,设置其 src
属性为带有回调函数的跨域请求 URL,请求 URL 返回的是一些调用 JSONP 回调函数的脚本代码。这些脚本代码可以由 JS 引擎执行,获取跨域数据。
JSONP 的优点是兼容性好,缺点是只能发送 GET 请求。
以百度为例,需要从 http://www.baidu.com/sugrec
请求数据。可以写一个如下的代码:
let script = document.createElement("script");
script.src = "http://www.baidu.com/sugrec?wd=a&callback=callback";
document.body.appendChild(script);
function callback(data) {
console.log(data);
}
CORS
CORS(Cross-Origin Resource Sharing)是一种现代的跨域请求数据的方法。
CORS 的实现原理是在服务器端进行设置。当客户端发起跨域请求时,服务器返回一个特殊的 HTTP 头部 Access-Control-Allow-Origin
,指定客户端的域名或 IP,说明要允许哪些源访问资源。
CORS 的优点是比 JSONP 更安全,缺点是需要在服务器端进行配置。
以 Node.js 为例,需要在服务器端设置 CORS:
const http = require("http");
http.createServer((req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
// 设置允许访问的域,* 代表允许所有域
res.writeHead(200, {"Content-Type": "text/plain"});
res.end("Hello World!");
}).listen(8888);
代理
代理方法是指通过本地服务器转发请求,从而间接访问目标服务器的数据。通过代理服务器访问远程服务器,前端 Java 虽然可以解决跨域问题,但会多一次网络请求的延迟,同时也多占用了一定的服务器带宽。
以 Axios 作为 HTTP 请求库,需要从 http://api.example.com/data.json
请求数据。可以写一个如下的代码:
axios.get("/api/data.json").then(response => {
console.log(response);
});
在本地服务器使用代理将 /api/data.json
的请求转发到 http://api.example.com/data.json
即可:
const http = require("http");
const request = require("request");
http.createServer((req, res) => {
if (req.url === "/api/data.json") {
request("http://api.example.com/data.json").pipe(res);
} else {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World!");
}
}).listen(8888);
在前端代码中,保持不变,请求地址仍然是 /api/data.json
。
代码演示
以下是代码演示:
示例一:JSONP
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONP 示例</title>
</head>
<body>
<script>
function handleData(data) {
console.log(data);
}
let script = document.createElement("script");
script.src = "//api.flickr.com/services/feeds/photos_public.gne?tags=cat&format=json&jsoncallback=handleData";
document.body.appendChild(script);
</script>
</body>
</html>
示例二:CORS
以下是 Node.js 代码:
const http = require("http");
http.createServer((req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.writeHead(200, {"Content-Type": "text/plain"});
res.end("Hello World!");
}).listen(8888);
以下是前端代码:
fetch("http://localhost:8888")
.then(response => response.text())
.then(data => console.log(data));
示例三:代理
以下是 Node.js 代码:
const http = require("http");
const request = require("request");
http.createServer((req, res) => {
if (req.url === "/api/data.json") {
request("http://api.example.com/data.json").pipe(res);
} else {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World!");
}
}).listen(8888);
以下是前端代码:
axios.get("/api/data.json").then(response => {
console.log(response);
});
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:AJAX javascript的跨域访问执行 - Python技术站