全面分析ajax跨域访问原因及解决方案

2023-05-16

文章目录

    • 引言
    • 什么是ajax跨域问题
    • 为什么会发生ajax跨域访问
    • 解决思路
    • 方法一:浏览器禁止检查
    • 方法二:jsonp解决
      • 【jsonp是什么】
      • 【用jsonp后台需要改动】
      • 【jsonp原理】
      • jsonp有什么弊端
    • 方法三:解决跨域
      • 3.1 被调用解决(后台处理)
        • 简单请求和非简单请求
        • 带cookie的跨域
        • 带自定义头的跨域
        • nginx和apache
        • SPRING框架解决跨域
        • 总结
      • 3.2 调用方解决(前台)
      • nginx
      • apache

引言

若想自己实践ajax跨域访问的例子,要编写后台服务代码及前台页面代码。网上很多文章都有贴代码都说过怎么解决这个问题,这篇文章主要是分析产生的原因和解决的思路。

什么是ajax跨域问题

前台调用后台服务接口的时候,如果这个接口不是同一个域的就会产生跨域问题。现在的开发模式是前后台分离发展,前后台开发是独立,所以就会出现前台大量调用后台接口的场景,只要不是同一个域就产生跨域问题。
比如我开发的是http://localhost:8080
ajax调用公司的接口http://xxx.com/xxx/xx/x
这就会报跨域错

为什么会发生ajax跨域访问

三个原因,三个同时满足才产品跨域问题
1.浏览器限制
2.跨域
3.是XHR请求

  1. 浏览器限制
    很多人认为发生跨域问题是服务器后台不允许前台调用,其实这个观点是错误的,真正原因是浏览器出于安全考虑,当发现是跨域时会进行校验,校验不通过就会报跨域安全问题。说白了就是浏览器多管闲事,不是服务器后台不允许调用。
    【验证】
    发出请求,报错:跨域安全问题
    在这里插入图片描述
    在network里查看
    在这里插入图片描述
    在这里插入图片描述
    可以看出返回值是200,Respon也是正确的,从这里看出服务器后台没有任何限制并且处理了,是浏览器报错。
  2. 跨域
    协议/域名/端口不一致都是跨域。在本地实践时,前台地址是8081端口,请求的是8080端口,所以说跨域了。虽然域名都是localhost
  3. XHR请求(XMLHttpRequest请求)
    这点很重要。如果不是XHR请求,就算是跨域浏览器也不会报错。
    浏览器只对XHR(XMLHttpRequest)请求有同源请求限制,而对script标签src属性、link标签ref属性和img标签src属性没有这这种限制,利用这个“漏洞”就可以很好的解决跨域请求。JSONP就是利用了script标签无同源限制的特点来实现的,当向第三方站点请求时,我们可以将此请求放在< script >标签的src属性里,这就如同我们请求一个普通的JS脚本,可以自由的向不同的站点请求:
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

在network里查看
在这里插入图片描述
发现跨域也没关系。
在这里插入图片描述
JQuery的ajax方法对JSONP方法进行了封装,使用起来很方便。
这三个同时满足才有可能发生跨域安全问题

解决思路

针对三个原因解决
在这里插入图片描述

  1. 浏览器限制
    只要有办法让浏览器不去限制,指定参数让浏览器不去做校验,但价值不大,因为需要每个人都做改动,而且这个改动是客户端的改动。客户是不会愿意的- -
  2. XHR请求
    不发这个类型的。解决方案是jsonp。动态创建一个script在script里面发出跨域请求.后面会讲解
  3. 跨域
    jsonp的解决方案有很多弊端,无法满足现在的开发要求。所以jsonp用得越来越少了,那么重点就要放在解决跨域上。
    有两种解决思路,一个是用被调用方修改代码,让它支持跨域,支持基于http协议关于跨域方面的要求而做的修改。也就是说,从A域名调用B域名的时候,在B域名返回的信息里面加入一些字段,告诉浏览器我允许A域名调用,那么浏览器只要通过检验它就不会报跨域安全问题。这叫支持跨域
    如果被调用方不是我们自己公司的,没法修改。这就是第二种思路,从调用方修改,这种思路是隐藏跨域,意思是我们通过一个代理,从浏览器发出去的都是A域名的请求,在代理里面把指定的URL转到B域名里面,在浏览器看来就是同一域名,不会报跨域错误。

方法一:浏览器禁止检查

命令行参数启动:
DOS打开浏览器并加一些参数,参数作用就是禁止做校验。这个新开的浏览器不会报错,所以跨域问题是前台的校验。
用户是不会愿意这样去打开浏览器的,多麻烦
在这里插入图片描述

方法二:jsonp解决

【jsonp是什么】

json的一种补充使用方式,不是官方协议,但也是个协议约定,利用‘script标签请求资源可以跨域’来解决跨域的。

【用jsonp后台需要改动】

先对前端代码改动,主要是dataType那里。
前台代码修改
发现报语法错误,jsonp是动态创建一个script标签,script标签返回的应该是js代码(比如引jquery库返回js代码),但现在服务器后台没有做任何改动,返回的还是一个json对象,所以浏览器把json对象和字符串当作js代码来解析,所报错。所以使用jsonp后台是需要改动的

【jsonp原理】

查看network
在这里插入图片描述
可以看出普通的ajax返回的是json,jsonp返回的是js
在这里插入图片描述
再看jsonp请求后面自动加了callback=一长串,双击点开如下
在这里插入图片描述
发现刚才callback=的一长串就是返回的js代码的函数名。而数据,这个json对象是作为参数返回的。

所以可以看出jsonp的实现原理是:
jsonp是个协议约定。jsonp请求发出时自动加一个callback参数(jq库自己实现),后台发现有callback就知道这是jsonp请求,它就会把返回的数据由json变为js(后台处理),而js的内容就是一个函数调用。函数名为callback值,返回的数据作为返回的参数。

【加深印象】
为了更好理解我们来验证一下
我打开慕课网,再打开network,发现里面只有一个xhr请求
在这里插入图片描述
双击点开
在这里插入图片描述
发现里面是个json对象,在地址后面手动加一个callback参数,如下
在这里插入图片描述
发现此时返回的是一个以wangyue为函数名,json为返回参数的函数
说明其后台有对jsonp的支持。
在淘宝上找到了jsonp的应用
在这里插入图片描述

jsonp有什么弊端

  1. 服务器需要改动代码支持
    那万一接口不是自己的代码,就无能为力了
  2. 只支持get方法
    原理是动态创建script来发出请求,只能用get方法
  3. 发出的不是xhr请求
    有很多新的特性,比如异步事件等。而jsonp没有

方法三:解决跨域

3.1 被调用解决(后台处理)

【思路】:后台在响应头Response Headers增加字段,告诉浏览器我允许跨域调用。

浏览器是先执行后判断,那么浏览器如何判断是跨域请求?
在这里插入图片描述
跨域请求的请求头里多了一个origin字段。这个字段的值是当前的域名信息。
就是说,浏览器发现这个请求是跨域的时候就会加在请求头Request Headers里加一个origin字段,这个字段里的值是当前域名。等请求返回来,它就会检查响应头Response Headers里面有没有允许跨域的信息,如果没有就会报错。
所以在后台进行修改
使其返回一个带有Access-Control-Allow-Methods(允许的方法)和Access-Control-Allow-Origin(允许的域)字段的Response Headers. *是代表所有
在这里插入图片描述

简单请求和非简单请求

之前说浏览器是先执行后判断。
浏览器在发送跨域请求的时候会判断一下是简单请求还是非简单请求,简单请求:先执行后判断。如果是非简单请求,会先发一个预检命令,检查通过之后才会真正把跨域请求发出去。
详见链接:举例说明简单请求与非简单请求

带cookie的跨域

Access-Allow-Control-Origin:*是否满足所有场景
错。不能满足带cookie的跨域请求。
带cookie时候Access-Allow-Control-Origin只能全匹配,不能使用星号,还要加一个access-control-allow-credentials: true这个字段。
比如csdn中的一个请求如下:
在这里插入图片描述
那如果想支持别的域呢?
(后台处理)可以在请求头里得到orgin字段,把它给响应头的Access-Allow-Control-Origin,那这样就可以支持所有域的跨域调用了。

带自定义头的跨域

(后台处理)在请求头里得到access-control-request-headers字段信息,把它给响应头的access-control-allow-headers,那这样就可以支持所有自定义头

nginx和apache

在实际应用里跨域请求都是从调用方的浏览器发送到被调用方的http服务器,http服务器再把请求转到应用服务器,应用服务器处理之后返回到http服务器,http服务器再把响应转回给调用方浏览器。如下图所示
在这里插入图片描述
那就在两个地方可以增加响应头字段,一个时应用服务器用filter增加,另一个是被调用方HTTP服务器增加。前端:需要把调用的域名改一改,需要把请求发送到被调用方的http服务器而不是应用服务器。(之前在应用服务器用filter处理)

虚拟主机:多个域名指向一个服务器,服务器根据不同的域名将请求转到不同的应用服务器。看上去好像有一个主机,其实是多个主机。

以nginx为例,apache思路也是如此只是写法不同

在这里插入图片描述

SPRING框架解决跨域

之前说的解决方案都和具体的框架没有关系。好比filter是每个web应用都有的。如果使用的是spring框架那么解决跨域非常简单。直接加个注解就可以了。
@CrossOrigin
这个注解可以加在类上也可以加在方法上,加在类上就是该类内的所有方法都支持跨域

总结

为支持跨域服务端增加的五个响应头:
access-control-allow-methods:*//支持所有方法
access-allow-control-origin:从origin获取//支持带cookie的所有域
access-control-allow-credentials: true//支持cookie
access-control-allow-headers:从access-control-request-headers获取//支持自定义头
access-control-max-age:3600//一个小时之内的预检命令缓存

可以直接在应用服务器用filter处理增加字段/但大多数实际应用里是在http服务器增加

3.2 调用方解决(前台)

当无法修改被调用方的时候,就可以采取隐藏跨域的解决思路。
在这里插入图片描述
跨域请求经过调用方的http服务器的反向代理转发到被调用方的服务器,在浏览器上面看不到任何的跨域请求。
【反向代理】:你访问同一个域名的两个不同url,它最后会去到两个不同服务器

nginx

要对http服务器nginx/apache进行配置
注意:此处8080是后台地址,8081是前台地址
在这里插入图片描述
再改下前台代码
在这里插入图片描述
把这个改为代理之后的地址
启动nginx,这时客户端不能访问8081端口,让所有的请求经过http服务器,所以要访问a.com
隐藏跨域和支持跨域最大的不同是我们调用的url,隐藏跨域的解决方案上我们调用的url都是本域的所以都是相对地址,而之前支持跨域的解决思路里,这里必须是绝对地址。浏览器看到都是相对地址,都是同一个域的地址,所以不会有任何跨域问题。

apache

给它增加一个虚拟主机,再虚拟主机里把跨域请求做一个代理。打开apache的配置文件,找到虚拟主机的配置文件,增加一个节点
在这里插入图片描述
在这里插入图片描述
再改下前端代码里的url
在这里插入图片描述
打开a.com,没有报错,查看network里的请求地址
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

全面分析ajax跨域访问原因及解决方案 的相关文章

随机推荐

  • Navicat如何连接远程服务器的MySQL

    前言 xff1a 运行环境及工具 Navicat for Mysql 腾讯云轻量级服务器一台 xff08 Centos 7 xff09 Mysql 8 0 24 xff08 远程服务器内安装的 xff09 Xshell7 xff08 连接操
  • 警告!你的隐私正在被上亿网友围观偷看!

    你的隐私正在被上亿万网友围观偷看 xff01 事情要从一款被推荐到烂的软件说起 Everything 这个软件想必很多同学都有听过 xff0c 是一款非常好用的文件搜索软件 xff0c 很多同学把它设置为开机必启动项之一 简单来说 Ever
  • Ubuntu安装JDK教程

    Ubuntu安装JDK教程 jdk的下载和安装 xff1a 1 打开浏览器 xff0c 输入jdk的官网地址 xff1a https www oracle com java technologies javase downloads htm
  • 面试官:如何让主线程等待所有的子线程执行结束之后再执行?我懵了

    使用Thread的join方法 package com qcy testThreadFinish 64 author qcy 64 create 2020 09 09 17 05 23 public class Case1 public s
  • 【亲测可用】 Mac/Linux 安装中文版 man 帮助命令

    Mac Linux 安装中文版 man 帮助命令 其中的需要下载的两个 安装包我上传到 csdn 了 xff0c 网络不好的可以直接 获取 不需要用 wget 下在 xff0c 虽然 wget 是很稳定 xff0c 但是国内的网络 还是太菜
  • 安卓android一种沉浸式状态栏和导航栏并可设置渐变和图片的方法

    安卓android一种沉浸式状态栏和导航栏并可设置渐变和图片的方法 介绍 网络上流传的状态栏导航栏沉浸的方式有很多 xff0c 但是在我使用的时候都失效了 xff0c 在官网也没找到合适的例子达到期望 xff0c 根据情况判断是由于目前版本
  • Python 循环结构

    在python中 xff0c 循环结构有for循环和while循环两种 1 while循环 while循环结构格式 xff1a while 条件表达式 xff1a 条件执行体 当条件表达式判断为真时 xff0c 就执行条件执行体中的内容 如
  • windows terminal + oh-my-posh 2022 [保姆级]配置教程

    windows terminal 43 oh my posh 2022 版配置教程 目录 windows terminal 43 oh my posh 2022 版配置教程 总览 1 下载powershell 2 安装字体 下载并安装字体至
  • DataBinding的基本使用(五)

    DataBinding的基本使用 五 DataBinding基本使用包括以下内容 xff1a 单纯的摆脱findviewbyid 绑定基本数据类型及String 绑定Model数据 绑定事件 通过静态方法转换数据类型 通过运算符操作数据 自
  • idea快捷键大全

    实用快捷键 Ctrl 43 或 Ctrl 43 Shift 43 注释 xff08 或者 xff09 Ctrl 43 D 复制行 Ctrl 43 X 删除行 快速修复 alt 43 enter modify cast 代码提示 alt 43
  • 自定义组件实现v-model

    在项目中需要做一个标题展开框 xff0c 点击展开才会显示下面的内容 因为多个地方都需要这样的可展开标题 xff0c 所以做了一个自定义组件 组件需要一个双向绑定的值 xff0c 控制展开 缩放 于是就思考 xff0c 父向子可以用prop
  • linux下提示bash:command not found

    如果新装的系统 xff0c 运行一些很正常的诸如 xff1a shutdown xff0c fdisk的命令时 xff0c 悍然提示 xff1a bash command not found 那么 首先就要考虑root 的 PATH里是否已
  • k8s与pod概念

    此文章为学习过程中根据网上资源整合总结 文章目录 1 为什么需要k8s1 1 应用部署模式的演进1 11 模式对比1 12 各模块介绍 1 2 管理大量的容器 k8s 2 ks8的集群架构3 pod k8s调度的最小单元3 1 一个 pod
  • git在http协议切换账号/输错账号密码如何更改

    掩面哭泣 xff0c 为什么提交总会出问题 这次是因为我push到gerrit上的时候第一次用错成了自己的账号 xff0c 然后想更改成公司的 xff0c 不再跳出登录界面了 xff0c 改不了 因为只有公司账号上设置了agreement
  • 【vue】利用prettier插件规避烦人的eslint报错和代码不规范

    本文主要包括两点 xff1a 大家协同开发代码各异 xff0c eslint加上 64 vue prettier采取recommended 43 prettier组合可使得代码更规范使用vscode的prettier插件在修改保存时自动格式
  • 前端理解base64

    一 背景 xff1a ascii码 字符 61 gt 二进制 计算机中所有数据的存储都是以二进制模式 xff0c 比如想要存储abcd需将其转化为二进制 xff0c 具体用哪些二进制来表示哪个符号 xff0c 有一个统一的编码规则 xff0
  • antd使用相关笔记

    文章目录 modal设置样式无效checkboxform设置值 modal设置样式无效 因为挂在div外 xff0c 所以用less时包在该组件的根div下的css样式设置无效 xff0c 需设置 xff1a span class toke
  • vue实例的生命周期详解

    Vue实例的生命周期 简介 此篇文章说的是最简单的单个VUE组件的生命周期 官网中的长图诠释了Vue实例从创建 xff0c 运行到销毁的整个过程 从vue实例的创建 xff0c 运行 xff0c 销毁期间 xff0c 总是伴随着各种各样的事
  • vue实例和组件的区别

    引言 上次写vue单组件项和路由的时候 xff0c 想到一个问题 new Vue 是一个Vue实例 xff0c 那么组件是Vue实例吗 xff1f 分析 之前说了 xff0c 有两种开发方式 一个是基于浏览器的 xff08 即直接在scri
  • 全面分析ajax跨域访问原因及解决方案

    文章目录 引言什么是ajax跨域问题为什么会发生ajax跨域访问解决思路方法一 xff1a 浏览器禁止检查方法二 xff1a jsonp解决 jsonp是什么 用jsonp后台需要改动 jsonp原理 jsonp有什么弊端 方法三 xff1