跨域AJAX总结

栏目: Json · 发布时间: 4年前

内容简介:跨域是指不同协议、域名、端口下访问js脚本。而当遇到跨域时,由于浏览器中同源策略是指限制了脚本与不同源的资源交互,而当中的这里只总结关于AJAX方面的跨域问题。同源政策规定,AJAX请求只能发给同源的网址,否则就报错。而解决方案一般有

跨域是指不同协议、域名、端口下访问js脚本。而当遇到跨域时,由于浏览器中 同源策略 的安全限制,导致不能正常执行,报类似以下的错误:

跨域AJAX总结

同源策略

什么是同源策略

同源策略是指限制了脚本与不同源的资源交互,而当中的 是以协议、域名和端口区分,以下情况为不同源:

http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
复制代码

限制范围

(1) Cookie、LocalStorage 和 IndexDB 无法读取。

(2) DOM 无法获得。

(3) AJAX 请求不能发送。
复制代码

AJAX

这里只总结关于AJAX方面的跨域问题。同源政策规定,AJAX请求只能发给同源的网址,否则就报错。而解决方案一般有 JSONPCORSWebSocket

JSONP

JSONP是服务器与客户端跨源通信的常用方法,这里我们写一个例子去探究 JSONP 的原理。

JSONP的实现原理

首先,网页通过添加一个 <script> 元素,向服务器请求JSON数据,这种做法不受同源政策限制。

render.js:

const express = require('express');
const app = express();

app.get('/jsonp', (req, res) => {
    const viewPath = `${__dirname}/jsonp.html`;
    res.setHeader('Content-Type', 'text/html');
    res.sendFile(viewPath);
});

app.listen(8081);
console.log(`listen 8081....`);
复制代码
jsonp.html:

<html>
    <body>
        <h1>jsonp test</h1>    
    </body>
    <script>
        function addScriptsTag (src) {
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.src = src;
            document.body.appendChild(script);
        }

        window.onload = function () {
            console.log('onload');
            addScriptsTag('http://127.0.0.1:8080/ip?callback=foo');
        }

        function foo (data) {
            console.log(`Your public IP address is:${data.ip}`);
        }

    </script>
</html>
复制代码

服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

const express = require('express');
const app = express();

app.get('/ip', (req, res) => {
    const callback = req.query.callback;
    res.send(`/**/ typeof ${callback} === 'function' && ${callback} ({"ip":"127.0.0.2"});`);
    // res.jsonp({ ip: '127.0.0.1' });// express自带jsonp更方便
});

app.listen(8080);
console.log(`listen 8080....`);
复制代码

最后前端收到返回的数据如下所示,浏览器就会执行该脚本,调用前面定义好的回调函数 foo

/**/ typeof foo === 'function' && foo ({"ip":"127.0.0.2"});
复制代码

使用

可以自行封装方法或者找第三方库去实现JSONP请求,比如jquery的jsonp方法。

CORS

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会 自动添加一些附加的头信息有时还会多出一次附加的请求 ,但用户不会有感觉。

两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

- HEAD
- GET
- POST

(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
复制代码

凡是不同时满足上面两个条件,就属于非简单请求

简单请求

输入 127.0.0.1:8081/cors ,浏览器正常进行一次简单的AJAX请求(使用axios):

render.js

const express = require('express');
const app = express();

app.get('/cors', (req, res) => {
    const viewPath = `${__dirname}/cros.html`;
    res.setHeader('Content-Type', 'text/html');
    res.sendFile(viewPath);
});

app.listen(8081);
console.log(`listen 8081....`);
复制代码
cros.html:

<html>

<body>
    <h1>cors test</h1>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
        axios({
                method: 'post',
                baseURL: 'http://127.0.0.1:8080/',
                url: '/user',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                },// 默认是applictaion/json,为非简单请求,所以为了测试需自定义
                data: {
                    firstName: 'Fred',
                    lastName: 'Flintstone'
                },
            })
            .then(function (response) {
                console.log(response);
            })
            .catch(function (error) {
                console.log(error);
            });
    </script>
</body>

</html>
复制代码

服务器通过中间件形式加上头部信息:

const express = require('express');
const app = express();

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://127.0.0.1:8081");
    next();
});

app.post('/user', (req, res) => {
    res.send('user ok');
});

app.listen(8080);
console.log(`listen 8080....`);
复制代码

这时候CORS就成功了,通信过程的头部信息:

请求头:

POST http://127.0.0.1:8080/user HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 44
Accept: application/json, text/plain, */*
Origin: http://127.0.0.1:8081
...

{"firstName":"Fred","lastName":"Flintstone"}
复制代码

响应头:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://127.0.0.1:8081
...

user ok
复制代码

其中起关键作用的是 OriginAccess-Control-Allow-OriginOrigin 浏览器请求时会带上,指明请求的来源。而响应头的 Access-Control-Allow-Origin 指明能够跨域请求资源的允许网址,多个用 逗号 隔开,如果写* 表明任意网址都可以。

非简单请求

当请求为非简单请求时,一次请求会分两次请求,分别是预检请求和正常的请求。

我们现在把上面AJAX请求方法变为 PUT

预检请求

请求就会先发一次预检请求。请求头如下:

OPTIONS http://127.0.0.1:8080/user HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: http://127.0.0.1:8081
...
复制代码

预检请求的方法为 OPTIONS ,表明请求时用来询问的。 Origin 依然表明请求来源。而新增的请求字段 Access-Control-Request-Method 表明接下来的CORS请求会到什么方法,能否使用。

这时服务器通过设置 Access-Control-Allow-Methods 来规定服务器支持的CORS请求方法:

res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE");
复制代码

正确返回后,响应头如下:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://127.0.0.1:8081
Access-Control-Allow-Methods: PUT,POST,GET,DELETE
Allow: PUT
...
复制代码

正常请求

正常请求的请求头:

PUT http://127.0.0.1:8080/user HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Content-Length: 44
Accept: application/json, text/plain, */*
Origin: http://127.0.0.1:8081
...

{"firstName":"Fred","lastName":"Flintstone"}
复制代码

回应:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://127.0.0.1:8081
Access-Control-Allow-Methods: PUT,POST,GET,DELETE
...

user ok
复制代码

和简单请求一样,请求写到 Origin ,回包携带 Access-Control-Allow-Origin

请求时支持携带Cookie

客户端, XMLHttpRequest 对象开启 withCredentials 属性。

JS写法:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
复制代码

axios开启选项即可:

withCredentials: true,
复制代码

服务端同意允许发送Cookie,通过设置头部:

res.header("Access-Control-Allow-Credentials",true);
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Linux从入门到精通

Linux从入门到精通

刘忆智、等 / 清华大学出版社 / 2010-1-1 / 59.00元

linux是目前增长最迅速的操作系统。本书由浅入深、循序渐进地向读者介绍linux的基本使用和系统管理。全书内容包括linux概述、linux安装、linux基本配置、桌面环境基本操作、shell基本命令、文件和目录管理、软件包管理、磁盘管理、用户与用户组管理、进程管理、网络配置、浏览网页、收发邮件、文件传输和共享、远程登录、多媒体应用、图像浏览和处理、打印机配置、办公软件的使用、linux编程工......一起来看看 《Linux从入门到精通》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具