前端跨域策略实践----cors,jsonp

原文地址: https://github.com/HolyZheng/...

了解几个跨域的方案,而且经过简单实践进行体会。javascript

如何实践?

可是,咱们如何进行实践呢?在哪发请求?向什么服务器发请求?很简单,就在当前网页,打开控制台,输入请求的代码html

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();

那么咱们就能够以当前页面url做为origin,向http://127.0.0.1:8888/ ,发送请求GET请求了。
同时在本地建立一个node服务前端

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

这样咱们就有服务器了,你能够很轻松的跟着这遍文章来实践了,而后从当前网页发送get请求到本地服务,理所固然跨域了。java

ps: github网站不行(本文最初再github上编写),会引起csp错误,此错误是用于防止内容注入攻击的,不得不说,大网站安全措施作得就是好,转战segmentfault作实践。

cors_error

1. cors

cors(跨域资源共享 Cross-origin resource sharing),它容许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它须要浏览器和服务器的同时支持。node

cors 分为两种请求,简单请求和非简单请求,关于cors的更详细介绍,推荐阮一峰老师的 跨域资源共享 CORS 详解,本文注重实践。

简单请求

正如上方的例子即是一个简单请求git

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();

如何解决此案例的跨域问题呢?
浏览器端,浏览器会自动在请求头中添加 origin 字段,咱们不须要操做。github

Request Headers: 
Origin: https://github.com

服务端,Access-Control-Allow-Origin属性,咱们须要服务端设置此属性,指定容许的请求源域名,能够经过指定为 *来指定因此域名。后端动起来:json

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain',
      'Access-Control-Allow-Origin': '*'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

重启服务,再尝试segmentfault

cors_error
此次没有再报错了,咱们看看服务器放回了什么
response
nice!跨域成功!后端

非简单请求

一样咱们在控制台输入一下代码进行put(非简单请求)

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.send();

毫无心外的报错

error_image

在进行非简单请求的时候,浏览器会先发送一次OPTION请求来“预检”(preflight)该请求是否被容许,请求头中会经过Access-Control-Request-MethodAccess-Control-Request-Headers来告诉服务器我须要用到的方法和字段,服务器经过返回的头部信息中的Access-Control-Allow-OriginAccess-Control-Allow-Method来告诉浏览器该跨域请求是否被容许。修改后端代码:

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

能够看到浏览器会先发送一个预检

option

当确认容许跨域以后,之后再发送该请求,就会省去预检处理,之间看成简单请求来操做。很明显,修改了后端代码后,此次的put请求时成功的。这里就不继续上图了。

cors总结

cors(跨域资源共享 Cross-origin resource sharing),它容许浏览器向跨域服务器发出XMLHttpRequest请求,从而克服跨域问题,它须要浏览器和服务器的同时支持。

  1. 浏览器端会自动向请求头添加origin字段,代表当前请求来源。
  2. 浏览器端须要设置响应头的Access-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Allow-Origin等字段,指定容许的方法,头部,源等信息。
  3. 请求分为简单请求和非简单请求,非简单请求会先进行一次OPTION方法进行预检,看是否容许当前跨域请求。

2. jsonp

jsonp的原理就是利用就是利用script标签没有跨域限制,能够经过script标签的src属性发送GET请求。咱们继续尝试,先把后端有关跨域的设置去掉,并重启服务

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

打开咱们的控制台输入一下代码,利用script标签进行jsonp请求

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = `http://127.0.0.1:8888/`;
document.head.appendChild(script);

能够看到,后端正常的返回了

request success !!!

并且该请求为GET请求

Request URL: http://127.0.0.1:8888/
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:8888
Referrer Policy: no-referrer-when-downgrade

可是咱们如今只是成功发送了一个跨域请求,可是咱们不像XMLHttpRequest那样能够在res.responseText中拿到数据,经过jsonp咱们该怎么拿到请求的数据呢?方法就是先后端约定一个callback字段名,来传递函数名,前端经过该函数来拿到数据。前端代码修改成:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = `http://127.0.0.1:8888/?callback=onBack`;
document.head.appendChild(script);
function onBack (res) {
  console.log(JSON.stringify(res));
  // 请求完后删除添加到页面上的script标签
  var head = document.head
  head.removeChild(script)
}

经过callback字段来传递函数名onBack,后端代码修改成

var http = require('http')
var urlTool = require('url')
// json 数据
var data = {'methods': 'jsonp', 'result': 'success'};

http.createServer(function (request, response) {
    var params = urlTool.parse(request.url, true)
    console.log(params)
    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });
    if (params.query && params.query.callback) {

      // callback(data)
      var str = `${params.query.callback}(${JSON.stringify(data)})`
    }

    response.end(str);
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

重启后端服务,而且在控制台输入代码,能够看到结果:

jsonp

咱们拿到了数据,而且经过onBack函数将他输出到了控制台上!

总结

  1. jsonp是一种跨域方案,他利用script标签没有跨域限制的特色,经过script标签的的src属性发送GET请求。
  2. 能够经过先后端约定一个字段名,好比callback,来传递一个函数名,从而使得前端可使用对应的callback函数,拿到数据,处理数据。

jsonp和cors比较

  1. CORS与JSONP的使用目的相同,可是比JSONP更强大。
  2. JSONP只支持GET请求,CORS支持全部类型的HTTP请求。JSONP的优点在于支持老式浏览器,以及能够向不支持CORS的网站请求数据。
同源策略:同源策略限制了一个源(origin)中加载文本或脚本与来自其它源(origin)中资源的交互方式,这是一个用于隔离潜在恶意文件的重要安全机制。若是两个页面拥有 相同 的 协议(protocol),端口(若是指定),和 主机,那么这两个页面就属于同一个源(origin)。
相关文章
相关标签/搜索