跨域

一、什么是跨域

当且仅当协议、域名、端口都相同时为同源

URL说明是否同源
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下的不同文件
http://www.a.com/folder1/a.js
http://www.a.com/folfer2/b.js
同一域名下的不同文件夹
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名、不同端口
http://www.a.com/a.js
https://www.a.com/b.js
同一域名、不同协议
http://www.a.com/a.js
http://70.32.92.74/b.js
域名与对应IP
http://www.a.com/a.js
http://www.b.com/b.js
http://script.a.com/b.js
主域相同,子域不同,相当于不同域名
http://www.baidu.com/a.js
http://baidu.com/b.js
主域相同,子域不同,相当于不同域名

二、跨域解决方案

1. 打破浏览器限制(临时解决方案)
  1. chrome浏览器设置打开属性绕过安全检查以避开跨域问题
2. JSONP
  1. 原理:script、img、iframe等含src属性的标签在请求资源时不会触发跨域问题。JSONP使用 script 标签来加载数据。

  2. 缺点
    (1) 只能发送 GET 请求
    (2) 发送的不是 XHR 请求,这样导致 XHR 请求中的很多事件都无法进行处理
    (3) 服务端需要改动

  3. 实现

    # 后端 flask
    # 域名 demo.com
    @app.route('api', methods=['GET'])
    def api():
    	req_data = request.args
    	func = req_data['callback']	# 获取函数名
    	res_data = { 'message': 'from backend: ' + req_data['message'] }
    	return func + '(' + json.dumps(res_data) + ')'	# 构建函数调用,需要返回的数据作为函数调用的参数
    
    // 前端 Vue
    methods: {
    	jsonp(){
    		// 在window中注册函数
    		window.handleResponse = (_data) => {
    			// _data: 此函数参数即为需要跨域传输的数据
    			alert(JSON.stringify(_data))
    		}
    		// 使用script的src执行API返回的函数调用
    		const script = document.createElement('script')
    		let func = 'handleResponse';	// 函数名需要与上方在window中注册的函数名一致
    		script.type = 'text/javascript'
    		script.src = 'http://demo.com/api?message=hello&callback=' + func;
    		// 挂载到document中执行API返回的函数调用
    		document.body.appendChild(script)
      		setTimeout(() => {
        		document.body.removeChild(script)
      		}, 2000)
    	}
    }
    

结合代码稍微再解释一下JSONP:

  • 服务器端:
    (1)最终将向客户端返回一个函数调用,函数调用中的参数就是需要传输的数据,函数名由客户端提供。
    # 示例代码中服务器的响应数据
    "handleResponse( { 'message': 'from backend: hello' } )"	# 其实就是一个字符串,内容为一次函数调用,参数为需要跨域的数据
    
  • 客户端:
    (1)使用<script>标签的src属性来调用API,并在url的请求参数中提供一个函数名<script>会自动执行所获取的代码/js文件,也就是会执行API返回的函数调用
    (2)因此,我们只需要在<script>脚本执行前,事先在全局window中注册一个函数名相同的函数,便能在该函数体内获取和操作该函数的参数,这个参数也就是需要跨域传输的数据。
    // window 中事先注册了函数handleResponse,函数的功能是把对象参数转为JSON字符串后alert出来
    window.handleResponse = (_data) => {
    	alert(JSON.stringify(_data))
    }
    // <script>标签自动调用API获取响应数据(一段函数调用代码),并执行这段代码
    // 其实就是相当于执行了下面的这行代码
    handleResponse( { 'message': 'from backend: hello' } );
    
3. CORS
  1. 优点:支持多种请求、在后端设置即可、API传输的数据格式无需变动
  2. 实现(未考虑cookie, CORS详解可以看阮一峰老师的这篇
    # 后端 flask
    @app.route('/api', methods=['POST'])
    def api():
        req_data = json.loads(request.get_data())
        response = make_response({'message': 'form backend: ' + req_data['message']})
        # 设置Access-Control-Allow-Origin。此处与设置'*'差不多,也可按实际需求添加一个白名单过滤器。
        response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] if request.headers['Origin'] else ''
        return response
    
  3. CORS请求头和响应头总结
  • 请求头:

    • Origin: 浏览器发出 Ajax 跨域请求之前会添加此头部,值为发送请求的域
    • Access-Control-Request-Method:使用了除 GET、POST、HEAD 请求方法之外的方法,浏览器会添加此头部,值为当前请求方法
    • Access-Control-Request-Headers:使用了自定义头部或除了Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID 之外的头部,浏览器会添加此头部,值为当前的请求方法
  • 响应头:

    • Access-Control-Allow-Origin: 表示服务端允许哪些域请求资源
    • Access-Control-Allow-Methods: 当客户端包含 Access-Control-Request-Method 请求头时,服务端需要响应该头部,值通常由 Reauest 的 header 中 Access-Control-Request-Method 取得
    • Access-Control-Allow-Headers: 当客户端包含 Access-Control-Request-Headers 请求头时,服务端需要响应该头部,值通常由 Reauest 的 header 中 Access-Control-Request-Headers 取得
    • Access-Control-Expose-Headers: 指出客户端通过 XHR 对象的 getResponseHeaders 方法可以获取的响应头有哪些
    • Access-Control-Allow-Credentials: 后端允许带 cookie 的跨域请求(前端需要相应设置xhr.withCredentials或者fetchcredential属性)
    • Access-Control-Max-Age: 预检请求的缓存时间

跨域介绍;JSONP、CORS详解
多种跨域解决方案

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值