处理跨域请求

浏览器具有同源策略,会禁止向与当前页面不同的域发送请求,只要是协议,域名,端口中有任何一个不同,都被当作是不同的域,这虽然是一种保护数据的机制,但是对我们开发来说确是个麻烦,解决办法有很多,这里介绍一下JSONP和CORS

先来理解一下浏览器这个同源策略是什么,就是浏览器禁止掉向其他域名发送的请求,其实是在请求回来的时候被禁掉的

哪些操作会受同源策略,哪些不会呢?

  requests模块不受影响,因为没有经过浏览器

  ajax发请求时,浏览器会限制(我们就是要解决这个问题)

  有src属性的都不受同源策略限制   -img,script,iframe

    但是注意,script中的src,拿到的数据会当作js代码执行,所以不能直接把数据放到src中

JSONP

  jsonp是一种机智的方式,本质就是在远程发送数据的时候,在数据外层套一个函数名,把数据以函数的形式返回这样才能被script识别

  在本地先定义一个函数,当远程发送过来数据,本地就当成一个函数执行真实数据就相当于参数

  jsonp本质就是创建一个script标签,把url放到src属性中,就是相当于发送了一个get请求,事实上jsonp只能发送get请求

用一个简单的示例来理解一下jsonp的本质

客户端的地址是:localhost:8000,要向服务端 localhost:8888 发送请求,获取数据,

利用jsonp来避开同源策略:

客户端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<button onclick="jsonp(‘http://127.0.0.1:8888/get_data?callback=func‘)">获取数据</button>{#通过参数向服务端发送函数名,这样就能实现动态生成函数名#}
<script>
    function func(arg) {
        console.log(arg);
        document.head.removeChild(tag);
    }

    function jsonp(url) {
        tag = document.createElement(‘script‘);//创建一个script标签,用来发送请求,注意是一个全局的变量,以便在func函数中删除
        tag.src = url;
        document.head.appendChild(tag); //在html的头文件中添加这个script标签
    }
</script>
</body>
</html>

服务端:

from django.shortcuts import HttpResponse

def get_data(request):    func_name = request.GET.get(‘callback‘)#从请求头中获取函数名    return HttpResponse(‘%s(数据)‘%func_name)#返回一个函数,把数据当作参数

1.jsonp就是利用script的src发送请求不会被受同源策略限制,然后通过src属性向服务端发送请求

2.script会把请求来的数据当成是js代码,所以服务端返回的数据不能直接是数据,会报错

3.把返回值封装成一个函数的形式,真实数据放在函数的参数中,客户端等收到后,从函数中拿到数据就行了

4.这个函数名最好是动态生成的,不然每次发送一个请求就要前后端商量好函数名,太麻烦

以上就是jsonp的原理

所以使用jsonp,本地需要定义一个函数,而远程需要把数据封装成一个函数

再来看看ajax如何实现跨域请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<button onclick="jsonp()">获取数据</button>
<script>
    function func(arg) {
        console.log(arg);
        document.head.removeChild(tag);
    }

    {# 这种实际上就是内部帮我们实现创建一个script标签#}
    function jsonp() {
        $.ajax({
            url:‘http://127.0.0.1/get_data‘,
            type:‘GET‘,
            dataType:‘JSONP‘,
            jsonp:‘callback‘,
            jsonCallback:‘func‘{# 这两行就是自动在url后面添加?callback=func #}

        })
    }
</script>

jsonp只能发送get请求,但是可不是所有的数据都能封装在参数中,想要发送post请求,还得用CORS



CORS跨站资源共享(Cross-Origin Resource Sharing)

再来看一下跨域请求时,浏览器的提示信息:

之所以ajax发送请求,返回的数据拿不到,是因为少了一点东西。提示缺少一个响应头,所以CORS的原理就是添加上这个响应头

只需要修改视图函数

from django.shortcuts import HttpResponse

def get_data(request):
    response = HttpResponse(‘数据‘)
    response[‘Access-Control-Allow-Origin‘] = ‘http://127.0.0.1:8888‘#这样表示允许这个地址访问
    #response[‘Access-Control-Allow-Origin‘] = ‘*‘#这样表示允许所有地址访问
    return response

这样就可以了,这是最简单的情况,本地不用做任何事,远程设置一个响应头

还有一种复杂点的情况:非简单请求

简单请求&非简单请求:

  简单请求的条件:  

    1.请求方式为 HEAD,GET,POST

    2.请求头中Content-Type的值是下面这三个中的一个

      application/x-www-form-urlencoded

      multipart/form-data

      text/plain

    同时满足以上两个条件时,才是简单请求,有一个不满足就是复杂请求


对于复杂请求,以PUT请求为例,会先发一个options请求,用来预检,对于预检请求,也要返回响应头

远程视图函数要这样处理:

def data(request):
    if request.method == ‘OPTIONS‘:
        #预检
        response = HttpResponse()
        response[‘Access-Control-Allow-Origin‘] = ‘*‘
        response[‘Access-Control-Allow-Methods‘] = ‘PUT‘#允许这个请求头  
        return response
    elif request.method == ‘PUT‘:
        #预检通过后真正的请求
        response = HttpResponse(‘数据‘)
        response[‘Access-Control-Allow-Origin‘] = ‘*‘

        return response

如果GET请求自定义请求头,也变成了复杂请求,也需要设置一下,允许这个请求头

比如自定义了一个请求头:xxx:yyyy

那远程代码中就要允许这个请求头

def data(request):
    if request.method == ‘OPTIONS‘:
        #预检
        response = HttpResponse()
        response[‘Access-Control-Allow-Origin‘] = ‘*‘
        # response[‘Access-Control-Allow-Methods‘] = ‘PUT‘
        response[‘Access-Control-Allow-Headers‘] = ‘xxx‘#允许这个请求头

        return response
    elif request.method == ‘PUT‘:
        #预检通过后真正的请求
        response = HttpResponse(‘数据‘)
        response[‘Access-Control-Allow-Origin‘] = ‘*‘

        return response

虽然复杂请求可以解决

但是,要尽量避免复杂请求,会增加服务器压力


总结,解决跨域请求,常用的有三种方式:requests模块,cors,jsonp

后两种直接从前端拿数据,不需要经过服务器,requests模块是先把请求发送到服务器,服务器向目标发送请求,再返回数据到本地

jsonp和cors相比,兼容性更好一点

参考博客:http://www.cnblogs.com/wupeiqi/articles/5703697.html

时间: 2024-11-01 20:22:46

处理跨域请求的相关文章

JSonP跨域请求

我们在通过自己的页面或程序通过ajax请求其它网站或服务时,会存在一个ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准.不过我们又发现,Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>.<img>.<iframe>).   于是可以判断,当前阶段如果想通过纯web端(ActiveX控件.服

跨域请求资源的几种方式

跨域请求资源的几种方式 由于浏览器同源策略,凡是发送请求URL的协议.域名.端口三者之间任意一与当前页面地址不同即为跨域. (1)JSONP(jsonp跨域get请求) 这种方式主要是通过动态创建一个script标签,浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行:(创建script标签向不同域提交http请求的不会被拒绝的方法,jsonp标签的src属性是没有跨域限制的) 实际项目中JSONP通常用来获取json格式数据,这时前后端通常约定一个参数callback,

AJAX跨域请求数据

由于浏览器的同源策略 ajax请求不可以接收到请求响应回来的数据 请求数据需要调用浏览器的内置构造函数 XMLHttpRequest() 进行 实例对象 var xhr = new XMLHttpRequest(); 注意点 在IE8之前支持的 ActiveXobject("Microsoft.XMLHTTP");  记住要进行兼容处理哦  在这里我就不写了 通过该对象进行获取 获取数据的四种状态  xhr.readyState 该属性保存着请求数据的几种状态 1.xhr.open(请

解决前端跨域请求的几种方式

利用 JSONP 实现跨域调用 说道跨域调用,可能大家首先想到的或者听说过的就是 JSONP 了. 1.1 什么是JSONP JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题.其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而 <script> 标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生 JSON 资料.用 JSONP 获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句. 1.2

JQuery的Ajax跨域请求的

JQuery的Ajax跨域请求的(Ajax) 什么是jsonp格式呢?API原文:假设获取的数据文件存放在远程server上(域名不同.也就是跨域获取数据),则须要使用jsonp类型.使用这样的类型的话,会创建一个查询字符串參数 callback=? .这个參数会加在请求的URL后面. server端应当在JSON数据前加上回调函数名.以便完毕一个有效的JSONP请求.意思就是远程服务端须要对返回的数据做下处理,依据client提交的callback的參数,返回一个callback(json)的

什么是跨域请求

昨晚在帮朋友解决问题的时候,遇到了一个问题,经过百度又让我理解了一个东西叫做:跨域请求.这个词其实不是第一次听到和看到,但是之前没有去细想,今晚将查找到的资料总个小总结. 浏览器均默认开启了同源策略,它指Ajax请求所在的页面和被请求的页面在协议.域名.端口均相同才能被访问,否则会提示如下错误: XMLHttpRequest cannot load xxxxxxx is not allowed by Access-Control-Allow-Origin. 之前还想过为什么,后来突然就明白了,很

PHP跨域请求nodejs

摘要:用nodejs作为服务器,php作为客服端进行跨域请求,并返回数据. 一:windows环境下的nodejs安装(以及express模板的安装):http://blog.uifanr.com/2013/03/12/472 http://www.veryhuo.com/a/view/39756.html 二:测试安装 1:在cmd中输入:node -v 若出现版本号,则安装成功. 2:在D 盘下新建一个文件  test_node.js : 1 var http = require("http

跨域请求问题

跨域请求,需要提供安全并且服务器认可的信息. 比如:A域名下的数据需要请求B域名下的一个方法,需要进行验证,或者可能需要获取B域名下cookie的某一个值,那么需要进行跨域请求. 如果我们使用普通的Ajax的json格式来进行请求,则会出现 XMLHttpRequest cannot load http://zhl.study.com/cross-domain.php. No 'Access-Control-Allow-Origin' header is present on the reque

Ajax 跨域请求 jsonp获取json数据

遇到Ajax的跨域请求出问题 找了中解决办法如下: 参考内容:http://justcoding.iteye.com/blog/1366102 由于受到浏览器的限制,该方法不允许跨域通信.如果尝试从不同的域请求数据,会出现安全错误.如果能控制数 据驻留的远程服务器并且每个请求都前往同一域,就可以避免这些安全错误.但是,如果仅停留在自己的服务器上,Web 应用程序还有什么用处呢?如果需要从多个第三方服务器收集数据时,又该怎么办? 理解同源策略 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的

跨域请求之JSONP

跨域恳求的方法有很多种, 1,iframe 2,document.domain 3,window.name 4,script 5,XDomainRequest (IE8+) 6,XMLHTTPRequest (Firefox3.5+) 7,postMessage (HTML5) 8,后台代理 ... 它们有各自的优缺点,回来的数据格局也各不同,应根据需要慎重挑选.比方iframe回来html片段就对比适合,费老劲用它回来JSON就因小失大了.这篇开端我将打造一个有用的跨域恳求东西Sjax.运用s