面试整理(2)跨域:jsonp与CORS

问题:跨域有哪些方法?jsonp的原理是什么?javascript

jsonp:html

先说jsonp,jsonp的主要原理是利用script标签的src能够跨域请求,听说有src属性的均可以跨域请求,但script标签返回的会直接执行,因此都是用script请求。jsonp=json+padding,padding是指服务器返回数据时把数据用padding(函数)包裹了起来。也就是说,通常状况下浏览器向服务器发送请求获得的都是数据(文本,XML,JSON),可是当采用JSONP技术时候,浏览器向跨域服务器发送请求,获得的是回调函数包住的JSON。此处JSON做为参数传入回调函数,而后再返回给浏览器。前端

这里写一个例子:其中后台用的nodejsjava

前端代码:index.htmlnode

<html>
    <head></head>
    <body>
        <div id="myDiv"></div>
    </body>
    <script type="text/javascript">
        function jsonpcallback(data){ console.log(data.text) } var s = document.createElement('script'); s.src="http://localhost:3000?callback=jsonpcallback"; document.body.appendChild(s); </script>
</html>

后台代码:server.jsajax

var http = require('http') var url = require('url') http.createServer(function(req,res){ var param = url.parse(req.url, true).query var callback = param.callback var data = { text: "hello world" } var resStr = callback+"("+JSON.stringify(data)+")" res.write(resStr) res.end() }).listen(3000)

上面的例子中,index.html中定义了一个jsonpcallback函数,而且把这个函数名通做为callback字段的值以get的请求(src的请求只能是get)发送给服务端。服务端接收到以后经过callback字段拿到回调函数名,而后用这个函数名包裹要返回的数据,造成一个字符串,发给前端json

例子在node环境下运行:node server.js,而后再运行index.html就能够看到前端跨域请求的结果。例子中因为index.html是本地的,因此跟服务器不一样源,普通的请求会被拒绝。后端

服务端写的时候要注意,返回的是一个很像函数调用的字符串,它不并非后台对callback函数的调用,因此要把返回的对象用JSON.stringify转化一下,再加上字符串的两个括号跨域

CORS:浏览器

jsonp说完以后,再说一个经常使用的跨域方法CORS。主要参考阮一峰大神的资料:http://www.ruanyifeng.com/blog/2016/04/cors.html

CORS分简单请求和非简单请求,同时知足下面两个条件的就是简单请求,不然就是非简单请求

简单请求:请求头经过Origin字段用来讲明,本次请求来自哪一个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否赞成此次请求。

 我在实际测试时先不使用关于cookie的一些可选字段,就简单的在前端设置Origin在后端设置Access-Control-Allow-Origin这种必须的字段来测试。

发现前端的ajax设置Origin字段会报错-》Refused to set unsafe header "Origin"

虽然不影响请求的发送,但设置的Origin字段是无效的,无论我设置什么或者不设置这个字段时查看Origin字段时它的值都是null,网上查了以后在stackoverflow上有人说那个Origin字段原本就应该是浏览器来设置的,本身设置不安全。

猜测只要浏览器发现请求的目标不是同源的,就会本身给报文加Origin字段。因此只要在后端设置Access-Control-Allow-Origin字段为*(表示接受任意Origin的请求)就能够了。

前端代码:简单的ajax便可

服务端代码:server.js

var http = require('http')  http.createServer(function(req,res){ res.writeHead(200, { 'Access-Control-Allow-Origin' : '*' }); res.write("hello world!") res.end() }).listen(3000)

 非简单请求:除去可选字段,在非简单请求中服务端还要指定Access-Control-Request-Method来表示本身接受的请求的方法,把以前的ajax中的方法从get改成put

前端代码:index.html

<html>
    <head></head>
    <body>
        <div id="myDiv"></div>
    </body>
    <script type="text/javascript">
        var xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP") xmlhttp.open("PUT","http://localhost:3000/",true)
        xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("myDiv").innerHTML=xmlhttp.responseText; } } xmlhttp.send() </script>
</html>

若是后台没有在Access-Control-Request-Method中添加put方法就会报错-》Failed to load http://localhost:3000/: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

后端代码:server.js

var http = require('http')
var url = require('url')

http.createServer(function(req,res){
    res.writeHead(200, {
        'Access-Control-Allow-Origin' : '*',
        'Access-Control-Allow-Methods' : 'GET, POST, PUT'
    });
    res.write("hello world!")
    res.end()
}).listen(3000)

添加了Access-Control-Request-Method:“PUT”后请求成功。

非简单方法浏览器会先发起一个method为OPTION的“预检”来跟服务器验证本身的请求是否是被容许,若是服务器回的头中没有请求的方法或者参数,那么浏览器就知道不容许,将不发送ajax请求。若是有,浏览器才会再发送那个ajax请求。

“预检”请求:

 

CORS和jsonp的区别主要在于:jsonp只支持get请求,而CORS支持全部类型的请求,只不过CORS要求至少IE10,jsonp兼容之前的版本。

相关文章
相关标签/搜索