关于web项目跨域问题详解
一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
总结,发生跨域必须同时满足3个条件:
1.发起请求和接收请求的协议,主机或者端口号不同,比如发起请求所在路径是http://localhost:8080,接收请求所在路径是http://localhost:8081,端口号不同,出现跨域问题
2.通过浏览器发起的请求,比如postman发起的请求就不会出现跨域问题
3.发起的请求类型是xhr(XMLHttpRequest)类型,比如json和document,javascript请求就不会出现跨域问题
为什么在浏览器地址栏输入同样的请求不会出现跨域请求报错,但是通过js等前端页面Ajax请求会出现跨域请求报错?
因为 跨域是需要有“主语”的,也就是说,是“来自某一源的代码”访问“另一源的资源”,而在地址栏中输入的请求,其主语是用户,是“用户”在访问资源,而不是“某个本地域”在访问资源。
二、什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url | 被请求页面url | 是否跨域 | 原因 |
http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.test.com/ | https://www.test.com/index.html | 跨域 | 协议不同(http/https) |
http://www.test.com/ | http://www.baidu.com/ | 跨域 | 主域名不同(test/baidu) |
http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口号不同(8080/7001) |
三,本地模拟跨域请求
随便找个外网,F12后数据一下脚本 回车执行
$.ajax({
url: "http://192.168.247.129:10000/edu/user/getUser",
type: "get",
contentType: "application/json",
dataType: "json",
success: function(data){
if(data.msg="success"){
alert("已提交成功");
}else{
alert("提交失败");
}
},
error: function(data){
alert("提交失败");
}
});
四、解决跨域问题
首先思考解决跨域问题思路:
1.浏览器做限制:disable-web-security,禁止浏览器做跨域请求限制,这个不现实,不可能让所有客户端浏览器都做这种限制
2.JSONP:类似于把xhr请求包装成script资源来进行请求,前端dataType 改为 "jsonp" ,后端也要相应做出协议修改,不建议使用,很多时候不符合使用场景
3.接收方(服务端):
(1) 注入Filter配置跨域
package com.study.domainserver.config;import com.study.domainserver.filter.AccessFilter;
import com.study.domainserver.intercepter.AccessIntercepter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.WebFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configuration
public class WebConfig extends WebMvcConfigurationSupport {/*** ***********谈谈Filter和Intercepter的区别************ Web应用请求执行顺序:Filter=>Servlet=>Intercepter=>Controller* 1.Filter是Servlet容器(Tomcat)支持的,只能放在Java ee项目中;Intercepter是Spring容器支持的,既可以放在Java ee也可以放在Java se项目中* 2.Filter比Intercepter先执行* 3.Filter通过dochain放行,Interceptor通过prehandler放行。* 4.Filter只在方法前后执行,Interceptor粒度更细,可以深入到方法前后,异常抛出前后* 5.Interceptor可以获取IOC容器中的各个bean,而Filter就不行,这点很重要,在Interceptor里注入一个service,可以调用业务逻辑*//*** 设置允许跨域方法一:添加过滤器Filter** @return*/@Beanpublic FilterRegistrationBean registFilter() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new AccessFilter());return filterRegistrationBean;}}
package com.study.domainserver.filter;import org.apache.commons.lang3.StringUtils;import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class AccessFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;//允许跨域请求地址(*表示全部,但是无法满足带cookie请求,因为cookie只能在当前域请求)String requestOrigin = request.getHeader("origin");response.setHeader("Access-Control-Allow-Origin", requestOrigin);//允许接收cookie和发送cookieresponse.setHeader("Access-Control-Allow-Credentials", "true");//允许请求的方法response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");//允许请求头(Content-Type:请求数据/媒体类型 x-requested-with:判断请求是异步还是同步 自定义header 比如 token)String requestHeaders = request.getHeader("Access-Control-Request-Headers");response.setHeader("Access-Control-Allow-Headers", requestHeaders);//response.setHeader("Access-Control-Allow-Headers", "Content-Type,x-requested-with");//浏览器缓存请求头信息,1800秒内,只会有1次请求,不会出现"OPTIONS"预请求,节约资源//response.setHeader("Access-Control-Max-Age", "1800");filterChain.doFilter(request, response);}
}
(2) 注入Intercepter配置跨域
package com.study.domainserver.config;import com.study.domainserver.filter.AccessFilter;
import com.study.domainserver.intercepter.AccessIntercepter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.WebFilter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configuration
public class WebConfig extends WebMvcConfigurationSupport {/*** ***********谈谈Filter和Intercepter的区别************ Web应用请求执行顺序:Filter=>Servlet=>Intercepter=>Controller* 1.Filter是Servlet容器(Tomcat)支持的,只能放在Java ee项目中;Intercepter是Spring容器支持的,既可以放在Java ee也可以放在Java se项目中* 2.Filter比Intercepter先执行* 3.Filter通过dochain放行,Interceptor通过prehandler放行。* 4.Filter只在方法前后执行,Interceptor粒度更细,可以深入到方法前后,异常抛出前后* 5.Interceptor可以获取IOC容器中的各个bean,而Filter就不行,这点很重要,在Interceptor里注入一个service,可以调用业务逻辑*//*** 设置允许跨域方法二:添加拦截器Intercepter** @param registry*/@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new AccessIntercepter()).addPathPatterns("/**");super.addInterceptors(registry);}}
package com.study.domainserver.intercepter;import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class AccessIntercepter implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//允许跨域请求地址(*表示全部,但是无法满足带cookie请求,因为cookie只能在当前域请求)//允许跨域请求地址(*表示全部,但是无法满足带cookie请求,因为cookie只能在当前域请求)String requestOrigin = request.getHeader("origin");response.setHeader("Access-Control-Allow-Origin", requestOrigin);//允许接收cookie和发送cookieresponse.setHeader("Access-Control-Allow-Credentials", "true");//允许请求的方法response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");//允许请求头(Content-Type:请求数据/媒体类型 x-requested-with:判断请求是异步还是同步 自定义header 比如 token)String requestHeaders = request.getHeader("Access-Control-Request-Headers");response.setHeader("Access-Control-Allow-Headers", requestHeaders);//response.setHeader("Access-Control-Allow-Headers", "Content-Type,x-requested-with");//浏览器缓存请求头信息,1800秒内,只会有1次请求,不会出现"OPTIONS"预请求,节约资源response.setHeader("Access-Control-Max-Age", "1800");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
(3)Controller类上加@CrossOrigin注解
package com.study.domainserver.controller;import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
@CrossOrigin
public class TestController {@GetMapping("msg")public Test testMsg() throws Exception {Test test = new Test();test.setId(1);test.setName("mike");System.out.println("/test/msg。。。。。。");return test;}
}
(4) Nginx配置服务端入口配置
#Nginx用户及组:用户 组。window下不指定
#user nobody;#工作进程:数目。根据硬件调整,通常等于CPU数量或者2倍于CPU。
worker_processes 1;#错误日志:存放路径。
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;#pid(进程标识符):存放路径
pid /usr/local/nginx/logs/nginx.pid;#一个进程能打开的文件描述符最大值,理论上该值因该是最多能打开的文件数除以进程数。
#但是由于nginx负载并不是完全均衡的,所以这个值最好等于最多能打开的文件数。
#LINUX系统可以执行 sysctl -a | grep fs.file 可以看到linux文件描述符。
worker_rlimit_nofile 65535;events {#使用epoll的I/O 模型。linux建议epoll,FreeBSD建议采用kqueue,window下不指定。use epoll;#单个进程最大连接数(最大连接数=连接数*进程数)worker_connections 1024;
}http {#设定mime类型,类型由mime.type文件定义include mime.types;default_type application/octet-stream;#服务器名字的hash表大小server_names_hash_bucket_size 128;#tcp_nodelay off 会增加通信的延时,但是会提高带宽利用率。在高延时、数据量大的通信场景中应该会有不错的效果#tcp_nodelay on,会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果tcp_nodelay on;#长连接超时时间,单位是秒keepalive_timeout 65;server {listen 80;server_name 192.168.247.130;location /{root html;index index.html index.htm;#解决跨域问题#允许跨域请求地址(*表示全部,但是无法满足带cookie请求,因为cookie只能在当前域请求)add_header Access-Control-Allow-Origin $http_origin;#允许接收cookie和发送cookieadd_header Access-Control-Allow-Credentials 'true';#允许请求的方法add_header Access-Control-Allow-Methods 'GET,POST,DELETE,PUT,OPTIONS';#允许请求头(Content-Type:请求数据/媒体类型 x-requested-with:判断请求是异步还是同步 自定义header 比如 token)add_header Access-Control-Allow-Headers $http_access_control_request_headers;#浏览器缓存请求头信息,1800秒内,只会有1次请求,不会出现"OPTIONS"预请求,节约资源#add_header Access-Control-Max-Age '1800';if ($request_method = 'OPTIONS') {return 204;}proxy_pass http://192.168.247.130:8081;} }
}
关于web项目跨域问题详解相关推荐
- proxytable代理不生效_proxyTable代理跨域使用详解
这次给大家带来proxyTable代理跨域使用详解,proxyTable代理跨域使用的注意事项有哪些,下面就是实战案例,一起来看一下. 什么是代理跨域 浏览器之间有同源策略,出于安全考虑不同域之间不允 ...
- jQuery中getJSON跨域原理详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp28 jQuery中getJSON跨域原理详解 前几天我再开发一个叫 河蟹工 ...
- web开发的跨域问题详解
2019独角兽企业重金招聘Python工程师标准>>> 本文由云+社区发表 做过 web 开发的同学,应该都遇到过跨域的问题,当我们从一个域名向另一个域名发送 Ajax 请求的时候, ...
- vue-admin-template解决跨域问题详解
vue-admin-template入门详解(后端springboot+sprngsecurity+jwt+redis) 自&如 2020-05-10 23:25:09 1232 收藏 10 ...
- jsonp 跨域原理详解
转载至:http://zha-zi.iteye.com/blog/1975116 JavaScript是一种在Web开发中经常使用的前端动态脚本技术.在JavaScript中,有一个很重要的安全性限制 ...
- 深和jsonp【转】 jsonpk跨域问题详解
取不到数据! 上周客户新买了服务器,原本在旧的服务器上放着客户的Web主页信息和一个后台程序(asp.net),在客户的主页中有一个动态显示最新消息的处理,这个处理就是通过ajax异步从那个后台程序中 ...
- Ajax 跨域请求详解
问题描述: 实际开发中,我们经常会看到这样的错误提示: XMLHttpRequest cannot load http://-- No 'Access-Control-Allow-Origin' he ...
- vue如何配置服务器端跨域_客户端(vue框架)与服务器(koa框架)通信及服务器跨域配置详解...
本篇博客主要说明: 前后端框架(本例中是vue和koa)如何发送请求?获取响应? 以及跨域问题如何解决? vue部分: import App from './App.vue' import Axios ...
- AJAX请求和跨域请求详解(原生JS、Jquery)
一.概述 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数 ...
最新文章
- Oracle 12c 新特性之 temp undo
- BZOJ 1412 [ZJOI2009]狼和羊的故事(最小割)
- 仿ios便签软件_手机便签软件误删怎么恢复?
- 深度学习(七)—— GAN
- 72. 编辑距离(JavaScript)
- 月薪一万在石家庄能过什么样的生活?
- 福建省计算机类考生,福建一档多投对考生是有利的,“滑档”的锅甩给计算机吗?...
- [WCF编程]10.操作:请求/应答操作
- 群晖 VMM虚拟机安装openwrt软路由做单臂旁路由
- ELK日志分析系统理论加实操演练!!
- 2021腾讯校招前端一面
- 安徽农业大学计算机考研分数线,安徽农业大学2019年考研复试分数线已公布
- One Piece Introduction
- java取0到999整数_Java中输入一个0到999的整数 怎么弄? 谢谢了、
- 反病毒工具-OllyDBG 和 UPX
- Apple Sign in with Apple(苹果授权登录PHP)
- 记一次简单学习MarkDown语法
- 【色彩管理】锐印添加ICC曲线教程
- top SRM526.5
- VSTO | C#快速开发电子签章插件
热门文章
- python3 django html 中文乱码_解决django后台管理界面添加中文内容乱码问题
- allergo 导出光辉配置_请教Allegro导出光绘文件的层要选择哪些层?
- mysql 代替分号_php – mysql FIND_IN_SET()用分号代替逗号
- win7 64位运行不了服务器,G6-e标准包可以装在win7 64位系统上吗?现在提示不能登陆到服务器...
- java svn配置环境变量,Android环境变量配置和安装SVN
- 设计个人介绍界面(用SWING控件),并添加各种组件练习
- 如果战斗机飞行员弹出,自动驾驶仪会接管飞机安全降落么?
- 第16课 “远程 Git文档库” 的基础操作
- Mongo 常用的server命令
- 禅道程序员的10条原则--转载--为了不忘