ajax跨域

一、 什么是跨域
前台调用后台接口时如果不在同一个域就会出现跨域问题,这里的域包括端口和域名。
二、跨域问题出现的条件
1、浏览器限制
浏览器发送请求时会进行安全校验 ,如果发现是跨域的就会报跨域安全问题。跨域问题出现的的原因与后台接口无关,是浏览器出于安全考虑所做的限制。
2、必须是XML(XmlHttpRequest)请求
那么怎么查看请求类型呢 ?
打开chrome调试工具,切换到network ,type就是请求类型
在这里插入图片描述
3、协议、域名、端口任何一个不同会产生跨域问题
下面是端口不同导致的跨域问题,直观一点浏览器端出现’access-control-allow-origin’字眼时 恭喜你碰到了跨域问题
在这里插入图片描述
三、解决思路
重点来来了,针对跨域问题出现的原因逐个击破
1、基于浏览器限制
设置浏览器,让其不进行安全校验。不同的浏览器设置方法不同 ,因为实用性不大,在这里不做介绍。
2、基于XHR
改变请求类型解决跨域问题是使用jsonp。jsonp是json的补充使用方式,不是官方协议,只支持get请求。
ajax请求案例如下

$.ajax({
url:base+'/test',
dataType:'jsonp',
jsonp:'callback'//默认为callback ,可定义。
success:function(json) {
}
})

jsonp解决需要改动后台代码,当不改动时会出现语法错误,例如
uncaught syntaxError:unexpected token:。
c#解决方案参考stackoverflow上面第一条评论
https://stackoverflow.com/questions/9421312/jsonp-with-asp-net-web-api/18206518#18206518

jsonp原理:请求类型发生变化,由xhr变成了script。jsonp请求是通过
动态创建script标签, 在script中将请求发出去 ,发送完成后自动销毁。
返回结果类型发生变化 ,由json变成js脚本,也就是Content-Type由application/json变成了application/javascript。

jsonp发生请求时会带上callback参数
callback是jsonp的约定 可以通过jsonp:"callback1"自定义指定,后台也应该相应改变。

打开Chrome查看jsonp请求,除了callback参数外还有一串数字,作用是防止请求被缓存,若需要缓存可以添加cache:true。
在这里插入图片描述

3、基于跨域
3.1 被调用方解决,后台接口做修改,支持跨域。
当发生跨域请求时请求头会多出一个origin字段(当前域信息字段)
在这里插入图片描述
如果是不带cookie的请求,在返回头中添加相对应的信息即可
c# 代码

Response.Headers["Access-Control-Allow-Origin"]= "http://localhost:7329";
Response.Headers["Access-Control-Allow-Methods"] = "GET";

返回头会增加如下信息
在这里插入图片描述
如果要容许所有的域和方法用*(通配符)代替
用通配符代替不是满足所有需求,下面我们先来弄明白什么是简单请求和非简单请求。
在发送http请求时,浏览会判断一个请求是简单请求还是非简单请求,如果是简单请求,就会先执行后判断是否跨域,如果是非简单请求,浏览器首先会发送一个预检命令 ,预检命令通过后再把请求发送出去。
简单请求的定义
方法包括 post、get。 head,请求header里面无自定义请求头
content-Type为以下几种:

text/plain
multipart/form-data
application/x-www-form-url

常见的非简单请求
put,delete方法的ajax请求,发送json格式的ajax请求,带自定义头的ajax请求。
下面我们来验证一个非简单请求

        $.ajax({
            url: "http://192.168.1.133:8054/demo/test/Index",
            dataType: 'json',
            contentType:'application/json;charset=utf-8',
            success: function (json) {
                let result = json;
                console.log(result);
            },
            error: function (res,type,err) {
               console.log(res,type,err)
            }
        })

当后端代码加了header为:

 Response.Headers["Access-Control-Allow-Origin"] = "*";
 Response.Headers["Access-Control-Allow-Methods"] = "*";

浏览器报错:Failed to load http://192.168.1.133:8054/demo/test/Index: Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
此时是预检命令报错,浏览器只发送了一次预检请求,类型为options
在这里插入图片描述
上面错误信息说明Content-Type没有被容许,我们后端代码变为

  Response.Headers["Access-Control-Allow-Origin"] = "*";
  Response.Headers["Access-Control-Allow-Methods"] = "*";
  Response.Headers["Access-Control-Allow-Headers"] = "Content-Type"; 

时请求成功,非简单请求会请求两次 ,预检命令通过后才会发真正的请求
在这里插入图片描述
预检命令会增加服务器负担 预检命令可以缓存
设置代码

Response.Headers["Access-Control-Max-Age"] = "3600";

缓存不代表不发送预检请求,而是预检命令缓存在浏览器。浏览器disable cache不勾选的情况下,只要请求过一次,当后端把Response.Headers[“Access-Control-Allow-Headers”] = “Content-Type”; 去掉时,也是只发送一次请求而且是成功的。

当请求带cook时

        $.ajax({
            url: "http://192.168.1.133:8054/demo/test/Index",
            dataType: 'json',
            xhrFields:{
            withCredentials:true
            },
            success: function (json) {
                let result = json;
                console.log(result);
            }
        })

cookie是被调用方的cookie,因为所读的cookie只能是本域的。
当带cookie请求时会报错:Failed to load http://192.168.1.133:8054/demo/test/Index: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard '’ when the request’s credentials mode is ‘include’. Origin ‘http://localhost:7329’ is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
意思是请求带cookie时不能用
这个通配符来代替域名。当我们把通配符换成固定域名后又报错: Failed to load http://192.168.1.133:8054/demo/test/Index: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’. Origin ‘http://localhost:7329’ is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
查看错误信息后,后端接口加一个条件

 Response.Headers["Access-Control-Allow-Credentials"] = "true";

请求成功
要有其他域名来调用呢,请求的域名可以从请求头的Origin字段来获取

    var dns = Request.Headers["Origin"];
    Response.Headers["Access-Control-Allow-Origin"] = dns;

带自定义头的请求

    $.ajax({
        url: "http://192.168.1.133:8054/demo/test/Index",
        dataType: 'json',
        headers: {
            "x-header1":"AAA"
        },
        beforeSend: function (xhr) {
            xhr.setRequestHeader("x-header2","BBB")
        },
        success: function (json) {
            let result = json;
            console.log(result);
        }
    })

请求后报错:Failed to load http://192.168.1.133:8054/demo/test/Index: Request header field x-header2 is not allowed by Access-Control-Allow-Headers in preflight response.意思是返回头中没有header1和header2的信息。加上两个header后请求成功。

   Response.Headers["Access-Control-Allow-Headers"] = "x-header1,x-header2";

header写死也是不理想的 可以获取请求头中的header赋值。

var headers = Request.Headers["Access-Control-Request-Headers"];
if(headers!=null)
    Response.Headers["Access-Control-Allow-Headers"] = headers;

总结一下

    //支持所有自定义请求头
    var headers = Request.Headers["Access-Control-Request-Headers"];
    if(headers!=null)
        Response.Headers["Access-Control-Allow-Headers"] = headers;
    Response.Headers["Access-Control-Allow-Methods"] = "*";

    //设置预检命令缓存周期
    Response.Headers["Access-Control-Max-Age"] = "3600";
    
    //支持cookie
    Response.Headers["Access-Control-Allow-Credentials"] = "true";

上述解决方案是跨域方的浏览器直接发送请求到被调用方的应用服务器,示例图:
在这里插入图片描述
实际应用中都是调用方浏览器先发送请求到被调用方的http服务器,http服务器再把请求转到应用服务器,应用服务器处理之后原路返回。
在这里插入图片描述
在这个过程中有两个地方可以增加响应头,http服务器和应用服务器,在应用服务器方添加响应头上面已经介绍过了 ,下面我们来说一说在http服务器(nginx)中添加响应头。
虚拟主机的概念:多个域名指向同一个服务器,服务器根据不同的域名转到不同的应用服务器。
被调用方虚拟主机的配置
打开服务器host文件, windows10 下host的路径为:C:\Windows\System32\drivers\etc
在host文件末尾添加127.0.0.1 b.com ,映射一个本地域名。
host文件无法保存请看这里:https://www.cnblogs.com/lwh-note/p/9005953.html
添加成功后b.com这个域名就是对应127.0.0.1这个ip地址。
然后在nginx.conf末尾添加(大括号内)

include vhost/*.conf //包涵vhost内所有.conf文件

在主目录创建vhost ,vhost下创建 cq.com.conf文件内容为

server{
	listen 80;//监听端口
	server_name b.com;//监听的域名
	location /{
	proxy_pass http://localhost:8080/;被调用方端口
    }
}

此配置意思是把所有的请求都转到8080。
nginx.exe -t 测试
start nginx.exe 启动
在 b.com.conf增加响应头

server{
	listen 80;//监听端口
    server_name cq.com;//监听的域名
    location /{
	proxy_pass http://localhost:8080/;被调用方端口
	add_header Access-Control-Allow-Methods *;
	add_header  Access-Control-Max-Age 3600;
	add_header Access-Control-Allow-Credentials true;
	add_header Access-Control-Allow-Origin $http_origin;
	add_header Access-Control-Allow-Headers $http_access-control-request-headers;
	//处理预检命令
	if ($request_method  ==OPTIONS) {
	return 200;
	}
}
}

nginx.exe -t 检测
nginx.exe -s reload 重新载入
nginx.exe -s stop
意思是把请求全部转到b.com
3.2 调用方解决,隐藏跨域。
通过调用方的http服务器的反向代理转发
反向代理 :访问同一个域名的两个不同的url 最终会去到不同的服务器
nginx配置
在本机增加 a.com,a.com表示调用方的虚拟主机
增加配置a.com.conf

server{
	listen 80;//监听端口
   server_name a.com;//监听的域名
   location /{
	proxy_pass http://localhost:8081/;调用方
    }
    location /ajaxserver{
	proxy_pass http://localhost:8080/;被调用方
}
}

请求接口全部换成/ajaxserve

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ajax(Asynchronous JavaScript and XML)是一种使用JavaScript编写的Web开发技术,用于在浏览器和服务器之间交换数据。但由于同源策略的限制,造成Ajax无法直接访问的资源。要实现访问,可以使用以下方法: 1. JSONP(JSON with Padding):JSONP是通过动态创建一个<script>标签,将访问资源的请求通过src属性添加到<script>标签上,并通过回调函数将数据返回到页面上,实现数据的获取。由于是通过<script>标签,返回的数据需要被包装在一个回调函数中返回,所以只能获取JSON格式的数据。 2. CORS(Cross-Origin Resource Sharing):CORS是在服务器端设置一些HTTP响应头信息来允许访问。其中最常用的设置是在服务器端添加Access-Control-Allow-Origin字段,允许指定的请求进行访问。CORS可以支持所有类型的HTTP请求。 除了以上两种方法外,还可以使用代理服务器、iframe和postMessage等方法来实现访问。选择合适的方法需要根据具体情况进行权衡,考虑到安全性、可用性和便捷性等因素。 要下载Ajax源码,可以通过搜索引擎或开源代码库查找相关的资源。在搜索引擎中输入“Ajax源码”或“Ajax下载”,即可找到一些开源的相关项目或代码片段。在开源代码库中,可以查找GitHub、GitLab等代码托管平台上的项目,根据需求选择合适的源码进行下载和使用。 在源码下载后,需要按照具体的使用方式和文档进行配置和集成到项目中。根据源码提供的API和示例,可以实现访问并获取到目标数据。需要注意的是,使用他人的源码时要遵循开源协议,并遵守相关的法律法规,确保代码的安全性和合规性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值