【ajax跨域】ajax跨域学习总结(二)(重要!!)

最常见的J2EE架构:

Apache/Nginx:HTTP服务器软件(静态服务器)

用户发出请求后,Apache/Nginx判断是静态请求还是动态请求(简言之,与用户数据有关的请求就是动态请求,反之静态请求。css/img都是静态请求),Apache/Nginx如果判断是静态请求,就直接处理请求,返回给客户端。如果是动态请求,就把请求转发到后台应用服务器tomcat,tomcat处理完请求,转到静态服务器,再到客户端。

Apache/Nginx两个作用:1.处理静态请求;2.负载均衡

跨域问题思路

第一种处理思路:直接从浏览器发出请求,请求被调用方。在被调用方上需要做相应的修改,这个修改基于http协议关于跨域请求的规定(就是在返回头中增加一些字段,告诉浏览器我这方允许调用)。

第二种处理思路:隐藏跨域。调用方从Apache/Nginx转出的。通过http服务器的转发,浏览器会认为请求是同一个域。

跨域解决方向

  • 被调方解决(思路一)

支持跨域的解决思路,是基于http协议关于跨域方面的规定。在响应头里增加指定字段,告诉浏览器我允许它调用。

  • 调用方解决(思路二)

基于隐藏跨域的思路,不会从浏览器直接请求被调用方,是从http服务器转发出去的。

假如调用方xxx.com,被调用方是yyy.com,第一种解决方法,在浏览器你会看到yyy.com,而第二种方法,浏览器看到都是xxx.com.

这两种方向,虽然都是修改的http服务器,但是他们的出发点,修改内容,修改目标都不一样的。第一种方法:修改的是被调用方的http服务器;第二种方法:修改的是调用方的http服务器。

被调用方解决(思路一)

该方法是在响应头增加字段。它可以增加在http服务器或者tomcat。所以

  • 服务器端实现(重点)
  • Nginx配置
  • Apache配置

1.被调用方解决---filter解决方案(服务器端实现

首先先明白几个问题

问题1:浏览器先执行还是先判断?

在后台可以打印出信息,并且请求状态为200,则说明浏览器先执行后判断。

问题2:浏览器如何判断的?

跨域请求header里有一个Orgin字段,是当前请求的域名信息。浏览器发现当前请求是跨域请求时,就会在请求头增加一个当前域名的字段,等请求返回后,检查有没有允许跨域的信息,如果没有,就会报错。

filter解决方案:

(ssm项目)服务器端:

在web.xml中加入

<filter>
   <filter-name>contextfilter</filter-name>
   <filter-class>com.wj.filter.WebContextFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>contextfilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
public class WebContextFilter implements Filter {
 
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
         
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse  httpServletResponse = (HttpServletResponse) response;
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "accept,content-type"); 
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "OPTIONS,GET,POST,DELETE,PUT"); 
        chain.doFilter(request, httpServletResponse);
         
    }
 
    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
         
    }
 
}

(springboot项目)

package com.wj.ajaxserver.filter;

import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * @创建人 wj
 * @创建时间 2018/11/23
 * @描述
 */
@Component
@ServletComponentScan
@WebFilter(urlPatterns = "/*", filterName = "crosFilter")
public class CrosFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        HttpServletRequest req = (HttpServletRequest) request;
        res.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
        res.addHeader("Access-Control-Allow-Methods", req.getHeader("Access-Control-Request-Method"));
//        带cookie时,需要的字段
        res.addHeader("Access-Control-Allow-Credentials","true");
//        非简单请求,需要加上这句.支持所有自定义头
        res.addHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));
//       告诉浏览器在1h内可以缓存这段信息,不用再发送预检命令。单位:s。
//       没有这句话,非简单请求的Method是OPTIONS
        res.addHeader("Access-Control-Max-Age", "3600");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

在springboot项目中我遇到了个问题,后台我加入filter后,请求在浏览器端还是报错。经过排查,发现在页面的测试方法中我用了没注明请求方式的ajax,在后台明确是@GetMapping请求,修改后,浏览器不再报错。


问题3:是不是所有请求都是先执行后判断?

不是,简单请求是先执行后判断,非简单请求是先判断后执行。


什么是简单请求、非简单请求

这两种请求在跨域上的差别:非简单请求在filter中加上需要加上(参考上面filter)

 res.addHeader("Access-Control-Allow-Headers", "Content-Type");
 res.addHeader("Access-Control-Max-Age", "3600");

带Cookie的跨域

在服务端filter中:另一种写法

res.addHeader("Access-Control-Allow-Origin", "*");

这种写法存在的问题是,当请求带cookie时,浏览器会报错。

带cookie请求,不要忘了filter中加入下面这句

res.addHeader("Access-Control-Allow-Credentials","true");

cookie是被调用方的cookie!!

带自定义头的跨域

//支持所有自定义头
res.addHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));

2..被调用方解决---nginx解决方案(nginx配置)

上述filter就是基于被调用方的tomcat处理跨域。在讲解nginx配置之前,了解一下,虚拟主机的概念。虚拟主机,是多个域名指向同一个服务器,服务器根据不同的域名把请求转发到不同的应用服务器,感觉有多个主机,实际上只有一个主机。比较官方的说法:

虚拟主机(Virtual Host Virtual Server)是使用特殊的软硬件技术,把一台计算机主机分成一台台"虚拟"的主机,每一台虚拟主机都具有独立的域名和IP地址(或共享的IP地址),具有完整的Internet服务器功能。在同一台硬件、同一个操作系统上,运行着为多个用户打开的不同的服务器程序,互不干扰;而各个用户拥有自己的一部分系统资源(IP地址、文件存储空间、内存、CPU时间等)。虚拟主机之间完全独立, 在外界看来, 每一台虚拟主机和一台独立的主机的表现完全一样。

nginx配置

1.打开C:\Windows\System32\drivers\etc\hosts

在后面填上一句:

127.0.0.1 wj.com

表示被调用方的域名

2.在nginx的文件夹conf新建一个名为vhost的文件夹(在vhost文件夹用来放置虚拟主机的配置文件)

3.在conf文件夹的文件nginx.conf中添加

意思是要nginx载入这个目录下的conf文件。

4.在vhost下新建一个名为wj.com.conf的文件,文件中用nginx的语法写上:

server{
	liaten 80;
	server_name wj.com
	
	location /{
		proxy_pass http://localhost:8080/;
	}
}

location 这句的意思是:把所有的请求都转到nginx的8080

5.配置完成后测试一下:

测试成功

6.启动nginx

去掉filter后,发现

wj.com.conf的文件中再加入:(注意if后有一个空格

server{
	listen 80;
	server_name wj.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;
		}
		
	}
}

再测试一下编写wj.com.conf是否正确,下面成功

重新载入:

修改js测试的请求被调用方的路径为

var base = "http://wj.com/test";

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值