-
2021-08-06 10:03:54
以PHP服务端为例。
页面ajax.php
//首先定义一个全局变量用于AJAX跨域返回值获取
$strJsonCallBack = $_REQUEST["jsoncallback"];
//定义一个测试数组
array['data'] = array('测试','再测试');
//再将数组进行JSON格式化,并在最前面加上刚刚定义的AJAX跨域返回值的标示
echo $strJsonCallBack."(".json_encode(array['data']).")";
exit;
?>
页面index.html
//访问JSON服务端返回值
var url = 'http://www.mudbest.com/ajax.php';
//&jsoncallback用于跨域获取的标示
$.getJSON(url+'&jsoncallback=?', {},function(data){
//获取返回的JSON字符串
data = data.data;
}
);
更多相关内容 -
Ajax跨域问题 解决方案
2018-11-09 15:13:41关于跨域,有N种类型,本文只专注于ajax请求跨域(,ajax跨域只是属于浏览器”同源策略”中的一部分,其它的还有Cookie跨域iframe跨域,LocalStorage跨域等这里不做介绍),内容大概如下: 什么是ajax跨域 o原理 o表现... -
SpringBoot解决ajax跨域问题的方法
2020-08-27 21:57:12主要为大家详细介绍了SpringBoot解决ajax跨域问题的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 -
PHP Ajax跨域问题解决方案代码实例
2021-01-19 23:45:04本文通过设置Access-Control-Allow-Origin来实现跨域。 例如:客户端的域名是client.runoob.com,而请求的域名是server.runoob.com。 如果直接使用ajax访问,会有以下错误: XMLHttpRequest cannot load ... -
关于ajax跨域问题的几种常见解决方案,附代码。
2019-03-01 14:24:40什么是跨域,跨域出现的场景,模拟跨域,springmvc下解决跨域,springboot下解决跨域。绝对原创。 -
解决ajax跨域问题
2016-12-28 16:59:18解决ajax跨域问题 -
IE9版本以下ajax 跨域问题可行解决方法
2020-12-11 04:08:06ajax跨域请求数据在谷歌火狐我本地IE11都是没问题的。 让测试就发现问题了,IE8下请求不到数据,然后我查看一下自己写的js看有没有不兼容问题,可是都没有啊,为什么就请求不到呢。 我把ajax的error打印出来提示no ... -
ajax跨域问题
2021-10-11 08:59:39跨域问题简单的说就是前台请求一个后台链接,发送请求的前台与后台的地址不在同一个域下,就会产生跨域问题。这里所指的域包括协议、IP地址、端口等。 1.跨域访问安全问题 后端代码: package cn.qs.controller;...跨域问题简单的说就是前台请求一个后台链接,发送请求的前台与后台的地址不在同一个域下,就会产生跨域问题。这里所指的域包括协议、IP地址、端口等。
1.跨域访问安全问题
后端代码:
package cn.qs.controller; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/test") @RestController public class TestController { @GetMapping("/get") public Map<String, Object> get(@RequestParam Map<String, Object> condition) { if (MapUtils.isEmpty(condition)) { condition = new LinkedHashMap<>(); condition.put("param", null); } return condition; } }
前端代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <script type="text/javascript" src="js/jquery-1.8.3.js" ></script> <body> </body> <script> + function test() { $.getJSON("http://localhost:8088/test/get.html", {}, function(res) { console.log(res); }); }(); </script> </html>
结果:虽然后端正常响应,但是JS报错,这就是跨域安全问题,如下:
js报错如下:
Failed to load http://localhost:8088/test/get.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access.
发生ajax跨域问题的原因:(三个原因同时满足才可能产生跨域问题)
(1)浏览器限制
发生ajax跨域的问题的时候后端是正常执行的,从后台打印的日志可以看出,而且后台也会正常返回数据。浏览器为了安全进行了限制,说白了就是浏览器多管闲事。
(2)跨域:
当协议、域名、端口不一致浏览器就会认为是跨域问题。
(3)XHR(XMLHttpRequest)请求,也就是ajax请求
如果不是ajax请求,不存在跨域问题(这个我们应该可以理解,浏览器直接访问以及a标签跳转等方式都不会产生跨域问题)。
2.解决思路
针对上面三个原因可以对跨域问题进行解决。思路如下:
(1)浏览器端:浏览器允许跨域请求,这个不太现实,我们不可能改每个客户端
(2)XHR请求使用JSONP(JSON with Padding)方式进行方式。它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。
(3)针对跨域问题解决:
被调用方:也就是服务器端接口,服务器允许跨域。但是如果某些情况服务器端不是我们写的就不可行了。
调用发:也就是JS客户端,隐藏跨域。通常是通过代理的形式隐藏跨域请求,使请求都类似于同一域下发出a标签。
3.浏览器禁止检查-从浏览器层次解决
比如chrom启动的时候设置参数关闭安全检查,如下:
chrome --disable-web-security --user-data-dir=g:/test
设置之后可以正常进行访问,这也进一步证明了跨域问题与后台无关。
4..采用JSONP解决,针对XHR原因
JSONP(JSON with Padding) 是一种变通的方式解决跨域问题。JSONP是一种非官方的协议,双方进行约定一个请求的参数。该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
JSONP发出的请求类型是script,不是XHR请求,所以可以绕过浏览器的检查。JSONP返回的是application/javascript,普通的xhr请求返回的是application/json。
JSONP的原理:通过向界面动态的添加script标签来进行发送请求。script标签会加上callback参数以及_,_是为了防止请求被缓存。
比如我们发送一个请求地址是http://localhost:8088/test/get.html?name=zhangsan&callback=handleCallback&_=123。后端看到有约定的参数callback,就认为是JSONP请求,如果XHR正常请求的响应是{success: true},那么后端会将回传的JSON数据作为参数,callback的值作为方法名,如: handleCallback({success: true}), 并将响应头的Content-Type设为application/javascript,浏览器看到是JS响应,则会执行对应的handleCallback(data)方法。
1.JSONP弊端
(1)服务器端代码需要改动
(2)只支持get方法,由于JSONP原理是通过script标签实现的,所以只能发送get请求
(3)不是XHR异步请求。所以不能使用XHR的一些特性,比如异步等。
2.测试JSONP
后端:增加一个advice
package cn.qlq.aspect; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; @ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { super("callback"); } }
前端:采用JSON包装的JSONP请求
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <script type="text/javascript" src="js/jquery-1.8.3.js" ></script> <body> </body> <script> + function test() { $.ajax({ type : "get", async:false, url : "http://localhost:8088/test/get.html?name=zhangsan", dataType : "jsonp",//数据类型为jsonp jsonp: "callback",//服务端用于接收callback调用的function名的参数 success : function(data){ console.log(data); }, error:function(){ alert('fail'); } }); }(); </script> </html>
结果:
(1)请求是script
请求头:
(2)查看响应数据头和数据:
数据如下:
/**/jQuery18309128178844464243_1575299406254({"name":"zhangsan","callback":"jQuery18309128178844464243_1575299406254","_":"1575299406287"});
补充:JSONP也可以自己定义返回的方法名称,默认是JSON生成的随机字符串
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <script type="text/javascript" src="js/jquery-1.8.3.js" ></script> <body> </body> <script> var handleJSONPresponse = function (res) { console.log(1); console.log(res); console.log(2); } function test() { $.ajax({ type : "get", async:false, url : "http://localhost:8088/test/get.html?name=zhangsan", dataType : "jsonp",//数据类型为jsonp jsonp: "callback",//服务端用于接收callback调用的function名的参数 jsonpCallback: "handleJSONPresponse", // callbacl的value值,不传由jquery随机生成 error:function(){ alert('fail'); } }); } test(); </script> </html>
查看请求数据:参数加_是为了防止浏览器缓存JS请求
查看响应数据:
结果:
5.跨域解决-被调用方解决(服务端允许跨域)
这里所说的被调用方一般也就是指的是服务端。
1.常见J2EE应用架构
客户端发送请求到http服务器,通常是nginx/Apache;http服务器判断是静态请求还是动态请求,静态请求就直接响应,动态请求就转发到应用服务器(Tomcat\weblogic\jetty等)。
当然也有省去中间静态服务器的应用,就变为客户端直接请求应用服务器。
2.被调用方解决
被调用方通过请求头告诉浏览器本应用允许跨域调用。可以从tomcat应用服务器响应请求头,也可以从中间服务器向请求头添加请求头。
(1)浏览器先执行还是先判断请求是XHR请求?
查看下面的简单请求与非简单请求的解释。
(2)浏览器如何判断?
分析普通请求和跨域请求的区别:
普通请求的请求头如下:
XHR的请求如下:
可以看出XHR请求的请求头会多出一个Origin参数(也就是域),浏览器就是根据这个参数进行判断的,浏览器会拿响应头中允许的。如果不允许就产生跨域问题,会报错。
补充:关于XHR请求头中携带X-Requested-With与Origin
我自己测试,如果用jquery的ajax访问自己站内请求是会携带X-Requested-With参数、不带Origin参数,如果访问跨域请求不会携带X-Requested-With参数,会携带Origin参数。
if ( !options.crossDomain && !headers["X-Requested-With"] ) { headers["X-Requested-With"] = "XMLHttpRequest"; }
1.被调用方过滤器中实现支持跨域
package cn.qs.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletResponse; /** * 允许跨域请求 */ @WebFilter(filterName = "corsFilter", urlPatterns = "/*") public class CorsFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse response2 = (HttpServletResponse) response; response2.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8020"); response2.setHeader("Access-Control-Allow-Methods", "GET"); chain.doFilter(request, response); } @Override public void destroy() { } @Override public void init(FilterConfig arg0) throws ServletException { } }
上面Access-Control-Allow-Origin是允许跨域请求的域, Access-Control-Allow-Methods 是允许的方法。
我们再次查看XHR请求头和响应头:
如果允许所有的域和方法可以用:
response2.setHeader("Access-Control-Allow-Origin", "*"); response2.setHeader("Access-Control-Allow-Methods", "*");
再次查看请求头和响应头:
这种跨域是不支持携带cookie发送请求的。
2.简单请求和非简单请求
简单请求是先执行后判断,非简单请求是先发一个预检命令,成功之后才会发送请求。
(1)简单请求:请求的方法为GET\POST\HEAD方法中的一种;请求的header里面无自定义头,并且Content-Type为:text/plain、multipart/form-data、application/x-www-form-urlencoded中的一种。
只有同时满足以上两个条件时,才是简单请求,否则为非简单请求
(2)非简单请求:put、delete方法的ajax请求;发送json格式的ajax请求;带自定义头的ajax请求。最常见的是发送json格式的ajax请求。非简单会发送两次请求:一个options的预检请求、预检请求根据响应头判断正确之后发送数据请求。
发送一个非简单请求:
后端:
package cn.qs.controller; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/test") @RestController public class TestController { @GetMapping("/get") public Map<String, Object> get(@RequestParam Map<String, Object> condition) { if (MapUtils.isEmpty(condition)) { condition = new LinkedHashMap<>(); condition.put("param", null); } return condition; } @PostMapping("/getJSON") public String getJSON(@RequestBody String param) { System.out.println(param); return param; } }
前端
function test() { $.ajax({ url: "http://localhost:8088/test/getJSON.html", type: "POST", data: JSON.stringify({name : "张三"}), contentType: "application/json;charset=utf-8", success: function(res) { console.log(res); } }); } test();
结果:(发送预检请求的时候报错)
控制台报错: (发送预检的响应头未设置需要的响应头)
Failed to load http://localhost:8088/test/getJSON.html: Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
修改filter
package cn.qs.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletResponse; /** * 允许跨域请求 */ @WebFilter(filterName = "corsFilter", urlPatterns = "/*") public class CorsFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse response2 = (HttpServletResponse) response; // 允许请求的域(协议://IP:port) response2.setHeader("Access-Control-Allow-Origin", "*"); // 允许请求的方法 response2.setHeader("Access-Control-Allow-Methods", "*"); // 正确的响应预检请求 response2.setHeader("Access-Control-Allow-Headers", "Content-Type"); chain.doFilter(request, response); } @Override public void destroy() { } @Override public void init(FilterConfig arg0) throws ServletException { } }
再次前端发送请求:(响应头增加Access-Control-Allow-Headers预检请求会正常响应,预检成功之后会发送正常的数据请求,所以看到是发出两个请求)
补充:预检命令可以缓存,过滤器向响应头增加如下响应头:(浏览器会缓存1个小时的预检请求)
// 缓存预检命令的时长,单位是s response2.setHeader("Access-Control-Max-Age", "3600");
1小时内发送非简单请求只会预检请求1次。我们可以用chrom的disable cache 禁掉缓存测试:
3.带cookie的跨域请求
同域下发送ajax请求默认会携带cookie;不同域发送cookie需要进行设置,前后台都需要设置。
(1)首先明白跨域请求需要后台进行设置:请求头的值 Access-Control-Allow-Origin 不能是*,必须是具体的域。需要根据请求头的Origin获取到请求的域之后写到响应头中。
(2)响应头也需要增加允许携带cookie的字段 。
// 允许cookie response2.setHeader("Access-Control-Allow-Credentials", "true");
(3)客户端发送ajax请求的时候需要withCredentials: true 允许携带cookie。A发ajax请求给B, 带着的是B的cookie, 还是受限于同源策略, ajax的Request URL是B, cookie就是B的
先在C:\Windows\System32\drivers\etc\hosts下面增加虚拟域名:
127.0.0.1 a.com 127.0.0.1 b.com
上面a.com 用于访问静态页面,b.com 用于接收后端请求。
后端过滤器修改
package cn.qs.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; /** * 允许跨域请求 */ @WebFilter(filterName = "corsFilter", urlPatterns = "/*") public class CorsFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // 允许访问的源 String headerOrigin = request.getHeader("Origin"); if (StringUtils.isNotBlank(headerOrigin)) { response.setHeader("Access-Control-Allow-Origin", headerOrigin); } // 允许访问的方法 response.setHeader("Access-Control-Allow-Methods", "*"); // 正确的响应预检请求 response.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 允许预检命令缓存的时间 response.setHeader("Access-Control-Max-Age", "3600"); // 允许cookie response.setHeader("Access-Control-Allow-Credentials", "true"); chain.doFilter(request, response); } @Override public void destroy() { } @Override public void init(FilterConfig arg0) throws ServletException { } }
后端Controller:
@GetMapping("/getCookie") public String getCookie(@CookieValue(value = "cookie1", required = false) String cookie, HttpServletRequest request) { System.out.println("cookie: " + cookie); System.out.println("Origin: " + request.getHeader("Origin")); return cookie; } @GetMapping("/setCookie") public String setCookie(HttpServletRequest request, HttpServletResponse response) { Cookie cookie2 = new Cookie("cookie1", "value1"); cookie2.setPath("/"); response.addCookie(cookie2); String cookie = "cookie1=value1"; return cookie; }
前端JS:
function test() { $.ajax({ type : "get", async: false, url : "http://b.com:8088/test/getCookie.html", xhrFields: { withCredentials: true }, success: function(res) { console.log("res: " + res); }, error:function(){ alert('fail'); } }); } test();
测试:
(1)如果直接执行前端不会传cookie,因为没有cookie。如下:(由于我们访问的服务是b.com域名,我们的cookie需要是b.com域名下的cookie)
首先我们访问后台 http://b.com:8088/test/setCookie.html 获取cookie,当然可以通过document.cookie进行设置
(2)接下来再访问后台:
请求头如下:
响应头如下:
(3)后台控制台日志
cookie: value1
Origin: http://a.com:80204.带自定义头的跨域请求
过滤器修改,根据自定义请求头在响应头中增加允许的请求头:
package cn.qs.filter; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; /** * 允许跨域请求 */ @WebFilter(filterName = "corsFilter", urlPatterns = "/*") public class CorsFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // 允许访问的源 String headerOrigin = request.getHeader("Origin"); if (StringUtils.isNotBlank(headerOrigin)) { response.setHeader("Access-Control-Allow-Origin", headerOrigin); } // 允许访问的方法 response.setHeader("Access-Control-Allow-Methods", "*"); // 正确的响应预检请求 // response.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 允许自定义的请求头(根据自定义请求头) String headers = request.getHeader("Access-Control-Request-Headers"); if (StringUtils.isNotBlank(headers)) { response.addHeader("Access-Control-Allow-Headers", headers); } // 允许预检命令缓存的时间 response.setHeader("Access-Control-Max-Age", "3600"); // 允许cookie response.setHeader("Access-Control-Allow-Credentials", "true"); chain.doFilter(request, response); } @Override public void destroy() { } @Override public void init(FilterConfig arg0) throws ServletException { } } Controller: @GetMapping("/getHeader") public JSONResultUtil<String> getHeader(@RequestHeader("x-header1") String header1, @RequestHeader("x-header2") String header2) { System.out.println(header1 + " " + header2); return new JSONResultUtil(true, header1 + " " + header2); }
前端:
<script> function test() { $.ajax({ url: "http://localhost:8088/test/getHeader.html", type: "get", headers: { "x-header1": "header1" }, beforeSend: function(xhr) { xhr.setRequestHeader("x-header2","header2"); }, xhrFields: { withCredentials: true }, success: function(res) { console.log(res); } }); } test(); </script>
结果:
我们禁调缓存会发送两条请求:
(1)预检请求
(2)第二条请求
5. 被调用方解决-nginx解决方案(替代上面的filter的作用)
这里用被调用方nginx解决是通过nginx代理之后增加所需的响应头。
我们还是基于上面的配置的本地域名。 下面 a.com 用于访问静态页面, b.com 用于接收后端请求。
127.0.0.1 a.com 127.0.0.1 b.com
(1)打开nginx/conf/nginx.conf,在最后的 } 前面增加如下:
include vhost/*.conf;
表示引入 当前目录/vhost/ 下面所有后缀为conf的文件。
接下来在当前conf目录创建vhost目录,并在下面创建b.com.conf文件,内容如下:
server { listen 80; server_name b.com; location /{ proxy_pass http://localhost:8088/; add_header Access-Control-Allow-Methods true; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Max-Age 3600; 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; } } }
注意
(0)前面的是设置监听域名是b.com、80端口,转发到 http://localhost:8088/
(1)nginx中请求头都是小写,-要用_代替。
(2)$http_origin可以取到请求头的origin。
(3)最后判断如果是预检请求,会直接返回200状态吗。
关于nginx的使用:
nginx检查语法:
E:\nginx\nginx-1.12.2>nginx.exe -t nginx: the configuration file E:\nginx\nginx-1.12.2/conf/nginx.conf syntax is ok nginx: configuration file E:\nginx\nginx-1.12.2/conf/nginx.conf test is successful
nginx重新加载配置文件:
nginx.exe -s reload
重启和停止
nginx.exe -s reopen nginx.exe -s stop
注释掉filter之后修改前台:异步访问 b.com, 会被请求转发到: http://localhost:8088/
function test() { $.ajax({ url: "http://b.com/test/getCookie.html", type: "get", headers: { "x-header1": "header1", "x-header3": "header3" }, beforeSend: function(xhr) { xhr.setRequestHeader("x-header2","header2"); }, xhrFields: { withCredentials: true }, success: function(res) { console.log(res); } }); } test();
(1)预检命令
(2)第二次正式请求
6. Spring注解跨域:@CrossOrigin
加在类上表示所有方法允许跨域,加在方法表示方法中允许跨域。
package cn.qs.controller; import java.util.LinkedHashMap; import java.util.Map; import org.apache.commons.collections.MapUtils; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.qs.utils.JSONResultUtil; @RequestMapping("/test") @RestController @CrossOrigin public class TestController { @GetMapping("/get") public Map<String, Object> get(@RequestParam Map<String, Object> condition) { if (MapUtils.isEmpty(condition)) { condition = new LinkedHashMap<>(); condition.put("param", null); } return condition; } @GetMapping("/getCookie") public String getCookie(@CookieValue(value = "cookie1") String cookie) { return cookie; } @PostMapping("/getJSON") public String getJSON(@RequestBody String param) { System.out.println(param); return param; } @GetMapping("/getHeader") public JSONResultUtil<String> getHeader(@RequestHeader("x-header1") String header1, @RequestHeader("x-header2") String header2) { System.out.println(header1 + " " + header2); return new JSONResultUtil(true, header1 + " " + header2); } }
6.调用方解决-隐藏跨域(重要)
被调用方解决跨域是通过nginx代理,将被调用方的请求代理出去,隐藏掉跨域请求。
(1)在nginx/conf/vhost下面新建a.com.conf,内容如下:
server { listen 80; server_name a.com; location /{ proxy_pass http://localhost:8020/; } location /server{ proxy_pass http://b.com:8088/; } }
解释: 监听 a.com 的80端口。 默认是/会转发到本地的8020端口,也就是前台页面所用的端口;如果是/server/ 开始的会转发到后端服务所用的路径。
(2)Controller修改
@GetMapping("/getCookie") public String getCookie(@CookieValue(value = "cookie1", required = false) String cookie, HttpServletRequest request) { System.out.println("cookie1: " + cookie); System.out.println("====================="); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String header = (String) headerNames.nextElement(); String value = request.getHeader(header); System.out.println(header + "\t" + value); } return cookie; }
(3)前端修改:(统一访问 /server 由nginx转发到后端服务)
function test() { $.ajax({ url: "/server/test/getCookie.html", type: "get", headers: { "x-header1": "header1", "x-header3": "header3" }, beforeSend: function(xhr) { xhr.setRequestHeader("x-header2","header2"); }, xhrFields: { withCredentials: true }, success: function(res) { console.log(res); } }); } test();
(4)首先设置cookie:(cookie是设置为a.com的cookie,nginx访问转发请求的时候也会携带到b.com)
查看cookie:
(5)刷新页面测试:
前端查看:可以看到前端请求发送至 a.com
请求头:
响应头:
后端控制台:(可以看到携带了x-requested-with参数,仍然是ajax请求,但是相当于同域请求。主机也是b.com(由nginx转发过来的请求))
cookie1: a.com.cookie ===================== host b.com:8088 connection close pragma no-cache cache-control no-cache accept */* x-header3 header3 x-requested-with XMLHttpRequest x-header2 header2 user-agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 x-header1 header1 referer http://a.com/%E6%99%AE%E9%80%9A%E7%9A%84%E6%B5%8B%E8%AF%95/index.html?__hbt=1575599926569 accept-encoding gzip, deflate accept-language zh-CN,zh;q=0.9 cookie cookie1=a.com.cookie
补充:调用方采用nodejs的express模块和http-proxy-middleware进行代理
(1)安装express模块和http-proxy-middleware模块:需要以管理员身份运行cmd
cnpm install --save-dev http-proxy-middleware cnpm install --save-dev express
(2)编写nodejs代理脚本:
const express = require('express'); const proxy = require('http-proxy-middleware'); const app = express(); app.use( '/server', proxy({ target: 'http://b.com:8088', changeOrigin: true, pathRewrite: {'/server' : ''} })); app.use( '/', proxy({ target: 'http://a.com:8020' })); app.listen(80);
注意:上面的顺序需要先代理/server,再代理/。否则会先匹配/。
(3)测试方法同上面nginx代理测试。
补充:nginx采用多进程结构
因为 Nginx 最核心的一个目的是要保持高可用性、高可靠性,而当 Nginx 如果使用的是多线程结构的时候,因为线程之间是共享同一个地址空间的,所以当某一个第三方模块引发了一个地址空间导致的段错误时、在地址越界出现时,会导致整个 Nginx 进程全部挂掉。而当采用多进程模型时,往往不会出现这样的问题。
master 进程被设计用来的目的是做 worker 进程的管理的,也就是所有的 worker 进程是处理真正的请求的,而 master 进程负责监控每个 worker 进程是不是在正常的工作、需不需要做重新载入配置文件、需不需要做热部署。我们启动一个nginx服务会启动两个进程,比如linux下面查看nginx相关进程:
[root@lawyer-test conf.d]# ps -ef | grep nginx root 19997 1 0 4月07 ? 00:00:00 nginx: master process ./nginx nginx 23141 19997 0 9月20 ? 00:00:01 nginx: worker process root 32666 20866 0 14:44 pts/7 00:00:00 grep --color=auto nginx
可以看到两个进程。一个 nginx master 进程是由 root 用户起的,进程 PID 是 19997。还有一个worker进程,是由19997进程起来的,进程ID是23141。
再次重新加载配置文件,查看进程如下:
[root@lawyer-test conf.d]# nginx -s reload [root@lawyer-test conf.d]# ps -ef | grep nginx nginx 11357 19997 0 14:47 ? 00:00:00 nginx: worker process root 12572 20866 0 14:48 pts/7 00:00:00 grep --color=auto nginx root 19997 1 0 4月07 ? 00:00:00 nginx: master process ./nginx
可以看到 worker 工作进程的进程ID发生改变。
补充: nginx -s 参数
-s 代表的是向主进程发送信号。其中信号有 4 个,stop, quit, reopen, reload。比如 nginx -s reload 命令就是重新加载配置文件。
补充: nginx 设置允许上传的最大文件
在nginx.conf配置文件中的http块中配置client_max_body_size参数
client_max_body_size 500M;
总结:
所谓的跨域请求是指XHR请求发送的时候 协议、域名、端口不完全一致的情况。只要有一个不同就是跨域。
如果用jquery的ajax访问自己站内请求是会携带X-Requested-With参数、不带Origin参数;如果访问跨域请求不会携带X-Requested-With参数,会携带Origin参数。
后端获取请求头的时候不区分大小写,比如说前端发送的请求头是 x-header1:header1。后端可以用 request.getHeader("X-HEADER1"); 接收。
-
详解ajax跨域问题解决方案
2020-11-30 19:36:29今天来记录一下关于ajax跨域的一些问题。以备不时之需。 跨域 同源策略限制 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味... -
关于C#中ajax跨域访问问题
2020-08-30 13:45:36最近做项目,需要跨域请求访问数据问题。下面通过本文给大家分享C#中ajax跨域访问代码详解,需要的朋友可以参考下 -
Ajax跨域问题及解决方案(jsonp,cors)
2021-01-19 17:08:00在前台通过动态添加script标签及src属性,表面看上去与ajax极为相似,但是,这和ajax并没有任何关系;为了便于使用及交流,逐渐形成了一中非正式传输协议,人们把它称作 jsonp 。 代码如下: html: <body> ... -
有关Ajax跨域问题的两种解决方法
2020-12-11 11:36:20Ajax跨域是前端开发中常见的问题,本文描述了以Google浏览器Chrome作为客户端和以Tomcat作为Web服务器的情况下的解决办法。 问题现象 当出现跨域访问的时候ajax通常会报类似如下错误: XMLHttpRequest cannot load ... -
Node.js配合node-http-proxy解决本地开发ajax跨域问题
2020-12-23 04:52:57前后端分离,本地前端开发调用接口会有跨域问题,一般有以下3种解决方法: 1. 后端接口打包到本地运行(缺点:每次后端更新都要去测试服下一个更新包,还要在本地搭建java运行环境,麻烦) 2. CORS跨域:后端接口... -
ajax跨域问题分析与springboot解决方法
2021-01-08 15:28:51ajax VsCode 插件 作用:模拟一个默认在5500端口的本地服务 jq ajax主要参数 $.ajax({ //请求方式 type:'POST', //发送请求的地址 url:'fzz.php', //服务器返回的数据类型 dataType:'json', //发送到服务器... -
关于Ajax跨域问题及解决方案详析
2020-10-17 01:50:33主要给大家介绍了Ajax跨域问题以及解决方案的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Ajax具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 -
解决ajax跨域问题的5种解决方案
2021-05-20 14:30:00跨域问题是针对JS和ajax的,html本身没有跨域问题。 查看浏览器开发者工具Console报错: Failed to load http://a.a.com:8080/A/FromServlet?userName=123: No ‘Access-Control-Allow-Origin’什么是跨域问题?
跨域问题来源于JavaScript的"同源策略",即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题。查看浏览器开发者工具Console报错:
Failed to load http://a.a.com:8080/A/FromServlet?userName=123: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://b.b.com:8080’ is therefore not allowed access.
http://www.abc.com/a/b 调用 http://www.abc.com/d/c(非跨域)
http://www.abc.com/a/b 调用 http://www.def.com/a/b (跨域:域名不一致)
http://www.abc.com:8080/a/b 调用 http://www.abc.com:8081/d/c (跨域:端口不一致)
http://www.abc.com/a/b 调用 https://www.abc.com/d/c (跨域:协议不同)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
跨域问题怎么解决?
1、响应头添加Header允许访问2、jsonp 只支持get请求不支持post请求
3、httpClient内部转发
4、使用接口网关——nginx、springcloud zuul (互联网公司常规解决方案)
解决方式1:响应头添加Header允许访问
跨域资源共享(CORS)Cross-Origin Resource Sharing这个跨域访问的解决方案的安全基础是基于"JavaScript无法控制该HTTP头"
它需要通过目标域返回的HTTP头来授权是否允许跨域访问。
response.addHeader(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
response.addHeader(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式解决方式2:jsonp 只支持get请求不支持post请求
用法:①dataType改为jsonp ②jsonp : “jsonpCallback”————发送到后端实际为http://a.a.com/a/FromServlet?userName=644064&jsonpCallback=jQueryxxx ③后端获取get请求中的jsonpCallback ④构造回调结构$.ajax({
type : “GET”,
async : false,
url : “http://a.a.com/a/FromServlet?userName=644064”,
dataType : “jsonp”,//数据类型为jsonp
jsonp : “jsonpCallback”,//服务端用于接收callback调用的function名的参数
success : function(data) {
alert(data[“userName”]);
},
error : function() {
alert(‘fail’);
}
});//后端
String jsonpCallback = request.getParameter(“jsonpCallback”);
//构造回调函数格式jsonpCallback(数据)
resp.getWriter().println(jsonpCallback+"("+jsonObject.toJSONString()+")");
JSONP实现原理
在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,即一般的ajax是不能进行跨域请求的。但 img、iframe 、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。利用当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据,而我们使用 JSONP模式来请求数据的时候服务端返回的是一段可执行的JavaScript代码。因为jsonp 跨域的原理就是用的动态加载
示例:
$.ajax({
url: 'http://192.168.10.46/demo/test.jsp', //不同的域 type: 'GET', // jsonp模式只有GET 是合法的 data: { 'action': 'aaron' }, dataType: 'jsonp', // 数据类型 jsonp: 'jsonpCallback', // 指定回调函数名,与服务器端接收的一致,并回传回来
})
其实jquery 内部会转化成
http://192.168.10.46/demo/test.jsp?jsonpCallback=jQuery202003573935762227615_1402643146875&action=aaron
然后动态加载
然后后端就会执行jsonpCallback(传递参数 ),把数据通过实参的形式发送出去。
使用JSONP 模式来请求数据的整个流程:客户端发送一个请求,规定一个可执行的函数名(这里就是 jQuery做了封装的处理,自动帮你生成回调函数并把数据取出来供success属性方法来调用,而不是传递的一个回调句柄),服务器端接受了这个 jsonpCallback函数名,然后把数据通过实参的形式发送出去
(在jquery 源码中, jsonp的实现方式是动态添加
解决方式3:httpClient内部转发
实现原理很简单,若想在B站点中通过Ajax访问A站点获取结果,固然有ajax跨域问题,但在B站点中访问B站点获取结果,不存在跨域问题,这种方式实际上是在B站点中ajax请求访问B站点的HttpClient,再通过HttpClient转发请求获取A站点的数据结果。但这种方式产生了两次请求,效率低,但内部请求,抓包工具无法分析,安全。$.ajax({
type : “GET”,
async : false,
url : “http://b.b.com:8080/B/FromAjaxservlet?userName=644064”,
dataType : “json”,
success : function(data) {
alert(data[“userName”]);
},
error : function() {
alert(‘fail’);
}
});@WebServlet("/FromAjaxservlet")
public class FromAjaxservlet extends HttpServlet{protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { //创建默认连接 CloseableHttpClient httpClient = HttpClients.createDefault(); //创建HttpGet对象,处理get请求,转发到A站点 HttpGet httpGet = new HttpGet("http://a.a.com:8080/A/FromServlet?userName="+req.getParameter("userName")); //执行 CloseableHttpResponse response = httpClient.execute(httpGet); int code = response.getStatusLine().getStatusCode(); //获取状态 System.out.println("http请求结果为:"+code); if(code == 200){ //获取A站点返回的结果 String result = EntityUtils.toString(response.getEntity()); System.out.println(result); //把结果返回给B站点 resp.getWriter().print(result); } response.close(); httpClient.close(); } catch (Exception e) { } }
}
解决方式4:使用nginx搭建企业级接口网关方式
www.a.a.com不能直接请求www.b.b.com的内容,可以通过nginx,根据同域名,但项目名不同进行区分。什么意思呢?这么说可能有点抽象。假设我们公司域名叫www.nginxtest.com当我们需要访问www.a.a.com通过www.nginxtest.com/A访问,并通过nginx转发到www.a.a.com
当我们需要访问www.b.b.com通过www.nginxtest.com/B访问,并通过nginx转发到www.a.a.com
我们访问公司的域名时,是"同源"的,只是项目名不同,此时项目名的作用只是为了区分,方便转发。如果你还不理解的话,先看看我是怎么进行配置的:
server {
listen 80;
server_name www.nginxtest.com;
location /A {
proxy_pass http://a.a.com:81;
index index.html index.htm;
}
location /B {
proxy_pass http://b.b.com:81;
index index.html index.htm;
}
}
我们访问以www.nginxtest.com开头且端口为80的网址,nginx将会进行拦截匹配,若项目名为A,则分发到a.a.com:81。实际上就是通过"同源"的域名,不同的项目名进行区分,通过nginx拦截匹配,转发到对应的网址。整个过程,两次请求,第一次请求nginx服务器,第二次nginx服务器通过拦截匹配分发到对应的网址。解决方式5:使用Spring Cloud zuul接口网关
我比较懒… -
完美解决AJAX跨域问题
2020-09-04 22:34:58我看到过很多人不愿意去正视ajax所存在的技术瓶颈,其实AJAX更应该是Ajax而不是AJAX,突出第一个A是想强调其实AJAX发扬的是一种异步传输的方法,而不是具体到底使用了哪种技术 -
Ajax跨域问题的解决办法汇总(推荐)
2021-01-19 19:40:04本篇将讲述一个小白从遇到跨域不知道是跨域问题,到知道是跨域问题不知道如何解决,再到解决跨域问题,最后找到两种方法解决ajax 跨域问题...这样反反复复改来改去好久都没能解决,于是求救同事,提醒可能是ajax跨域问 -
Javascript跨域和Ajax跨域解决方案
2019-08-08 01:08:10NULL 博文链接:https://sun123start.iteye.com/blog/2150778 -
解决前端跨域问题【ajax跨域问题】
2019-03-27 18:07:19作者:岁岁 ...来源:知乎 在接触前端开发起,跨域这个词就一直...关于跨域,有N种类型,现在我只专注于ajax请求跨域(ajax跨域只是属于浏览器”同源策略”中的一部分,其它的这里不做介绍),内容大概如下: 什么是ajax...作者:岁岁
链接:https://zhuanlan.zhihu.com/p/60019674
来源:知乎在接触前端开发起,跨域这个词就一直以很高的频率在我们学习工作中重复出现,最近在工作中遇到了跨域的相关问题,这里我把它总结记录一下。
关于跨域,有N种类型,现在我只专注于ajax请求跨域(ajax跨域只是属于浏览器”同源策略”中的一部分,其它的这里不做介绍),内容大概如下:
什么是ajax跨域?如何解决ajax跨域?如何分析ajax跨域?
一、什么是Ajax跨域
Ajax跨域的原理
ajax出现请求跨域错误问题,主要原因就是因为浏览器的“同源策略”。
CORS请求原理
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
基本上目前所有的浏览器都实现了CORS标准,其实目前几乎所有的浏览器ajax请求都是基于CORS机制的,只不过可能平时前端开发人员并不关心而已(所以说其实现在CORS解决方案主要是考虑后台该如何实现的问题)。
下面是一个简化版的实现原理图:
如何判断是否是简单请求?
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。
l 请求方法是以下三种方法之一:HEAD,GET,POST
l HTTP的头信息不超出以下几种字段:
Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
凡是不同时满足上面两个条件,就属于非简单请求。
ajax跨域的表现
现象一: No 'Access-Control-Allow-Origin' header is present on the requested resource,并且The response had HTTP status code 404
出现这种情况的原因如下:
l 本次ajax请求是“非简单请求”,所以请求前会发送一次预检请求(OPTIONS)
l 服务器端后台接口没有允许OPTIONS请求,导致无法找到对应接口地址
解决方案: 后端允许options请求。
现象二: No 'Access-Control-Allow-Origin' header is present on the requested resource,并且The response had HTTP status code 405
这种情况下:
l 后台方法允许OPTIONS请求,但是一些配置文件中(如安全配置),阻止了OPTIONS请求,才会导致这个现象
解决方案: 后端关闭对应的安全配置。
现象三: No 'Access-Control-Allow-Origin' header is present on the requested resource,并且status 200
这种情况下:
l 服务器端后台允许OPTIONS请求,并且接口也允许OPTIONS请求,但是头部匹配时出现不匹配现象,比如origin头部检查不匹配,比如少了一些头部的支持(如常见的X-Requested-With头部),然后服务端就会将response返回给前端,前端检测到这个后就触发XHR.onerror,导致前端控制台报错
解决方案: 后端增加对应的头部支持。
现象四: heade contains multiple values '*,*'
这种问题出现的主要原因就是进行跨域配置的人不了解原理,导致了重复配置,如:
l 常见于.net后台(一般在web.config中配置了一次origin,然后代码中又手动添加了一次origin(比如代码手动设置了返回*))
l 常见于.net后台(在IIS和项目的webconfig中同时设置Origin:*)
解决方案(一一对应):
建议删除代码中手动添加的*,只用项目配置中的即可;
建议删除IIS下的配置*,只用项目配置中的即可。
二、如何解决ajax跨域
一般ajax跨域解决就是通过JSONP解决或者CORS解决,如以下:(注意,现在已经几乎不会再使用JSONP了,所以这里重点介绍CORS)
CORS解决跨域问题
CORS的原理上文中已经介绍了,这里主要介绍的是,实际项目中,后端应该如何配置以解决问题,这里是一些常见的后端解决方案:
PHP后台配置:
PHP后台得配置几乎是所有后台中最为简单的,遵循如下步骤即可:
l 第一步:配置Php 后台允许跨域
l 第二步:配置Apache web服务器跨域(httpd.conf中)
原始代码:
改为以下代码:
Node.js后台配置(express框架):
Node.js的后台也相对来说比较简单就可以进行配置。只需用express如下配置:
JAVA后台配置:
JAVA后台配置只需要遵循如下步骤即可:
l 第一步:获取依赖jar包下载 cors-filter-1.7.jar, java-property-utils-1.9.jar 这两个库文件放到lib目录下。(放到对应项目的webcontent/WEB-INF/lib/下)
l 第二步:如果项目用了Maven构建的,请添加如下依赖到pom.xml中:(非maven请忽视)
其中版本应该是最新的稳定版本,CORS过滤器
l 第三步:添加CORS配置到项目的Web.xml中( App/WEB-INF/web.xml)
注意:以上配置文件请放到web.xml的前面,作为第一个filter存在(可以有多个filter的)
l 第四步:可能的安全模块配置错误(注意,某些框架中-譬如公司私人框架,有安全模块的,有时候这些安全模块配置会影响跨域配置,这时候可以先尝试关闭它们)
NET后台配置:
.NET后台配置可以参考如下步骤:
l 第一步:网站配置:
打开控制面板,选择管理工具,选择iis;右键单击自己的网站,选择浏览;打开网站所在目录,用记事本打开web.config文件添加下述配置信息,重启网站
如果配置仍然出问题,可以考虑增加更多的headers允许,比如:
l 第二步:其它更多配置,如果第一步进行了后,仍然有跨域问题,可能是:
l 接口中有限制死一些请求类型(比如写死了POST等),这时候请去除限 制
l 接口中,重复配置了Origin:*,请去除即可
l IIS服务器中,重复配置了Origin:*,请去除即可
代理请求方式解决接口跨域问题
注意,由于接口代理是有代价的,所以这个仅是开发过程中进行的。
与前面的方法不同,前面CORS是后端解决,而这个主要是前端对接口进行代理,也就是:
l 前端ajax请求的是本地接口
l 本地接口接收到请求后向实际的接口请求数据,然后再将信息返回给前端
l 一般用node.js即可代理
关于如何实现代理,这里就不重点描述了,方法和多,也不难,基本都是基于node.js的。搜索关键字node.js,代理请求即可找到一大堆的方案。
三、如何分析ajax跨域
抓包请求数据
第一步当然是得知道我们的ajax请求发送了什么数据,接收了什么,做到这一步并不难,也不需要fiddler等工具,仅基于Chrome即可
l Chrome浏览器打开对应发生ajax的页面,F12打开Dev Tools
l 发送ajax请求
l 右侧面板->NetWork->XHR,然后找到刚才的ajax请求,点进去
示例一(正常的ajax请求)
上述请求是一个正确的请求,为了方便,我把每一个头域的意思都表明了,我们可以清晰的看到,接口返回的响应头域中,包括了:
所以浏览器接收到响应时,判断的是正确的请求,自然不会报错,成功的拿到了响应数据。
示例二(跨域错误的ajax请求)
这个请求中,接口Allow里面没有包括OPTIONS,所以请求出现了跨域
这个请求中,Access-Control-Allow-Origin: *出现了两次,导致了跨域配置没有正确配置,出现了错误。更多跨域错误基本都是类似的,就是以上三样没有满足(Headers,Allow,Origin),这里不再一一赘述。
示例三(与跨域无关的ajax请求)
并不是所有的ajax请求错误都与跨域有关,所以请不要混淆,比如以下:
比如这个请求,它的跨域配置没有一点问题,它出错仅仅是因为request的Accept和response的Content-Type不匹配而已。
基本上都是这样去分析一个ajax请求,通过Chrome就可以知道了发送了什么数据,收到了什么数据,然后再一一比对就知道问题何在了。
最后,跨域是一个老生常谈的话题,网上也有大量跨域的资料,并且有不少精品。
-
jquery中ajax处理跨域的三大方式
2020-11-22 01:14:16由于JS同源策略的影响,因此js只能访问同域名下的文档。因此要实现跨域,一般有以下几个方法: 一、处理跨域的方式: 1.代理 2.XHR2 HTML5中提供的... ajax本身是不可以跨域的, 通过产生一个script标签来实 -
PHP处理Ajax请求与Ajax跨域问题
2020-10-20 10:50:55主要介绍了PHP处理Ajax请求与Ajax跨域问题的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 -
Ajax跨域访问解决方案
2019-04-01 01:09:29NULL 博文链接:https://exceptioneye.iteye.com/blog/1405495 -
js 跨域和ajax 跨域问题小结
2021-01-21 13:48:02ajax要跨域的话,可以用服务器去别的网站取内容,如asp.net的: 代码如下:public string GetUrlData(string url) { System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest....