跨域AJAX总结

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

内容简介:跨域是指不同协议、域名、端口下访问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);
复制代码

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

查看所有标签

猜你喜欢:

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

Code Reading

Code Reading

Diomidis Spinellis / Addison-Wesley Professional / 2003-06-06 / USD 64.99

This book is a unique and essential reference that focuses upon the reading and comprehension of existing software code. While code reading is an important task faced by the vast majority of students,......一起来看看 《Code Reading》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具