Ajax跨域问题及解决

前端之家收集整理的这篇文章主要介绍了Ajax跨域问题及解决前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

跨域问题的产生

前台调用后台接口,因为前台后台不在同一个域内产生跨越问题。

  • 浏览器限制
  • 跨域
  • XHR(XMLHttpRequest)请求

三个条件同时产生才能发生跨域问题。

解决思路

从浏览器角度解决

使用不检查跨域的方式启动浏览器

  1. **\chrome --disable-web-security --user-data-dir=g:\temp3

不存在任何的跨域问题,可以自由访问。

此种解决方法说明,跨域是浏览器限制的行为,跟后台没有任何的关系。

针对XHR使用JSONP访问

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。
JSONP是一种约定,非官方框架。
前端使用代码

  1. //每个测试用例的超时时间
  2. jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
  3. //每个请求接口的前缀
  4. var base = "http://localhost:8080/test";
  5.  
  6. //测试模块
  7. describe("ajax跨域测试",function () {
  8. //测试方法
  9. it("jsonp请求",function (done) {
  10. //服务器返回结果
  11. var result;
  12. $.ajax({
  13. url: base + "/get1",dataType: "jsonp",success: function (json) {
  14. result = json;
  15. }
  16. });
  17. //由于是异步请求,需要使用setTimeout来校验
  18. setTimeout(function () {
  19. expect(result).toEqual({
  20. "data": "get1 ok"
  21. });
  22. //校验通过,通知jasmine框架
  23. done();
  24. },100);
  25. });
  26. });

后端增加代码

  1. package com.fwj.ajax;
  2.  
  3. import org.springframework.web.bind.annotation.ControllerAdvice;
  4. import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice;
  5. @ControllerAdvice
  6. public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{
  7. public JsonpAdvice(){
  8. super("callback");
  9. }
  10. }

使用Jsonp后端需要做改动,需要返回非Json对象。

关于Jsonp成功的原因

  1. jsonp发送的请求是script请求,区别于xhr请求,不存在跨域的问题。
  2. 普通的xhr请求返回的是json数据对象,jsonp返回的是一个js脚本。
  3. 请求URL的不同,请求带有callback字段


    原理:jsonp请求中,对应后台中约定的callback,json代码内容就是callback的值作为函数名,返回的的数据作为函数的参数。

JSONP弊端

  1. 服务器端需要改动。
  2. 支持GET方法
  3. 发送的不是XHR请求,无法使用各种XHR各种优势。

调用解决跨域


需要被调用方在返回中添加指定的字段,允许对方调用

服务器端实现

调用发-Filter解决方案。

【简单请求】:
方法为GET,HEAD,POST,并且请求header里面无自定义头,Content-Type为text/plain,multipart/form-data,application/x-www-form-urlencoded中的一种。
浏览器对于简单是先执行拿到数据再判断。

【非简单请求】:
除简单请求之外都是非简单请求。
工作中常见的非简单请求:
1. put.delete方法的ajax请求。
2. 发送json格式的ajax请求。
3. 带自定义头的ajax请求。
浏览器对于非简单请求是先发送预检命令,然后再执行

在后端增加Filter配置,在响应头中添加需要的Header。

  1. import javax.servlet.*;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import java.io.IOException;
  5.  
  6. public class CrossFilter implements Filter {
  7. @Override
  8. public void init(FilterConfig filterConfig) throws ServletException {
  9.  
  10. }
  11.  
  12. @Override
  13. public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain) throws IOException,ServletException {
  14. HttpServletResponse response = (HttpServletResponse) servletResponse;
  15. HttpServletRequest request= (HttpServletRequest) servletRequest;
  16. String origin = request.getHeader("Origin");
  17. if(org.springframework.util.StringUtils.isEmpty(origin)){
  18. //允许所有的远程请求
  19. response.addHeader("Access-Control-Allow-Origin","*");
  20. }
  21. String headers = request.getHeader("Access-Control-Request-Headers");
  22. if(org.springframework.util.StringUtils.isEmpty(headers)) {
  23. //允许自定义头,网页可以请求各种内容类型
  24. response.addHeader("Access-Control-Allow-Headers",headers);
  25. }
  26. //允许所有的请求方式
  27. response.addHeader("Access-Control-Allow-Methods","*");
  28. //允许OPTIONS预检命令缓存3600秒
  29. response.addHeader("Access-Control-Max-Age","3600");
  30. //使Cookie生效
  31. response.addHeader("Access-Control-Allow-Credentials","true");
  32. //放行
  33. filterChain.doFilter(servletRequest,response);
  34. }
  35.  
  36. @Override
  37. public void destroy() {
  38.  
  39. }
  40. }

将此Filter加入Spring配置文件

  1. package com.fwj.ajax;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  6. import org.springframework.context.annotation.Bean;
  7.  
  8. @SpringBootApplication
  9. public class AjaxApplication {
  10.  
  11. public static void main(String[] args) {
  12.  
  13. SpringApplication.run(AjaxApplication.class,args);
  14. }
  15. @Bean
  16. public FilterRegistrationBean registerFilter(){
  17. FilterRegistrationBean bean =new FilterRegistrationBean();
  18. bean.addUrlPatterns("/*");
  19. bean.setFilter(new CrossFilter());
  20. return bean;
  21. }
  22. }

关于OPTIONS预检命令

OPTIONS它用于获取当前URL所支持方法。若请求成功,则它会在HTTP头中包含一个名为“Allow”的头,值是所支持方法,如“GET,POST”。

关于带Cookie类型的跨域

使用Cookie时”Access-Control-Allow-Methods”,不能为 *,必须使用全匹配。
Access-Control-Allow-Methods 需要为调用方的域名并且,Cookie需要存在于被调用方的域中。
并且需要设置

  1. Access-Control-Allow-Credentials : true

前端代码如下

  1. //测试方法
  2. it("getCookie请求",function (done) {
  3. //服务器返回结果
  4. var result;
  5. $.ajax({
  6. type:"get",url: base + "/getCookie",xhrFields:{
  7. withCredentials:true
  8. },100);
  9. });

Nginx配置

配置原理图

  1. server{
  2. listen 80;
  3. server_name b.com;
  4.  
  5. location/{
  6. proxy_pass http://localhost:8080/;
  7.  
  8. add_header Access-Control-Allow-Methods *;
  9. add_header Access-Control-Max-Age 3600;
  10. add_header Access-Control-Allow-Credentials true;
  11.  
  12. add_header Access-Control-Allow-Origin $http_origin;
  13. add_header Access-Control-Allow-Headers &http_access_control_request_headers;
  14. if ($request_method = OPTIONS){
  15. return 3600;
  16. }
  17. }
  18. }

Nginx技巧:

  1. //检查Nginx的配置时候正确
  2. ./Nginx -t

APACHE配置

Spring框架解决方

在需要跨域的Controller类或者需要跨域的方法增加注解

  1. @CrossOrigin

调用解决跨域

Nginx配置

使用反向代理

调用方的Nginx增加配置

  1. server{
  2. listen 80;
  3. server_name a.com;
  4. location/{
  5. proxy_pass http://localhost:8081/;
  6. }
  7.  
  8. location/ajaxserver{
  9. proxy_pass http://localhost:8080/test/;
  10. }
  11. }

调用方需要访问前缀地址 “/ajaxserver”

  1. eg:http:/a.com/ajaxserver/get1

APACHE配置

猜你在找的Ajax相关文章