No ‘Access-Control-Allow-Origin‘ header is present之 为什么会跨域及解决方案[通俗易懂]

No ‘Access-Control-Allow-Origin‘ header is present之 为什么会跨域及解决方案[通俗易懂]1浏览器的限制2跨域3浏览器发送的是XHR(XMLHttpRequest)请求当以上三个条件都满足时浏览器会抛出跨域请求异常(记住是浏览器抛出的异常,和服务端没太大关系),在讲跨域请求解决方案前先了解几个问题。1http请求中,哪些是常见的简单请求,哪些是非简单请求常见的简单请求:请求方法为:GET,HEAD,POST,请求header里面无自定义头,Conten…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1 浏览器的限制

2 跨域

3 浏览器发送的是 XHR (XMLHttpRequest)请求

当以上三个条件都满足时浏览器会抛出跨域请求异常(记住是浏览器抛出的异常,和服务端没太大关系),在讲跨域请求解决方案前先了解几个问题。

1 http请求中,哪些是常见的简单请求,哪些是非简单请求

常见的简单请求:请求方法为:GET ,HEAD,POST,请求header里面无自定义头,Content-Type为以下几种:text/plain  multipart/form-data application/x-www-form-urlencoded

常见的非简单请求 :请求方法为:put delete的ajax请求,发送json格式的ajax请求,带自定义头的ajax请求

2 浏览器在发送跨域请求时候,会有哪些过程

如果是简单请求,浏览器会先发送请求,然后判断服务器返的返回头中是否支持跨域请求,否则抛出跨域异常

如果是非简单请求,浏览器会先发出OPTIONS请求方法的检测命令,判断服务器是否支持跨域请求,如果支持则发送真正的请求,如果不支持则抛出跨域异常,因此一个非简单请求每次会发送两个请求,后面跨域解决方案会讲到缓存OPTIONS预检请求

跨域解决方案

No ‘Access-Control-Allow-Origin‘ header is present之 为什么会跨域及解决方案[通俗易懂]

方案1:  禁用浏览器跨域校验,即允许跨域访问,(这种方案不可取,不可能让所有的浏览器设置允许跨域访问)

谷歌浏览器禁用跨域校验: 创建一个快捷方式发送到桌面 ,快捷方式–》右键—》属性页面中的目标输入框里追加  –disable-web-security –user-data-dir=C:\Program Files (x86)\Google\Chrome\Application (注意:–user-data-dir的值就是浏览器安装目录。)不一定生效

方案2: 采用jsonp方式,需要后台和前台同时改动代码,

1 前台需要设置callback参数,如果使用的是jquery ajax 那么dateType属性设置为jsonp,jquery框架会自动设置参数名为callback的请求参数,也可以通过jsonp属性修改jsonp请求参数名,其他js框架根据具体api使用,

2 后台接收到callback参数后认为是jsonp请求,需要返回jsonp格式,普通json请求返回的content-Type是application/json,而jsonp返回的是application/javascript,同时也证明了jsonp请求服务端返回的是js脚本

3 jsonp请求参数名前后约定需要相同,例如jquery默认使用的是callback

弊端:jsonp 需要前后端都去修改代码,且jsonp是通过动态创建script脚本发送请求,仅支持 GET方法,jsonp发出的请求不是xhr请求,也是能解决跨域的原因

No ‘Access-Control-Allow-Origin‘ header is present之 为什么会跨域及解决方案[通俗易懂]

方案3 服务端解决跨域问题

通过编写filter在response对象中添加响应头,告诉浏览器允许跨域访问,* 号代码允许所有的请求域名,所有的请求方法跨域访问

@WebFilter("/*")
public class CORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        // 告诉浏览器允许所有的域访问
        // 注意 * 不能满足带有cookie的访问,Origin 必须是全匹配
        // resp.addHeader("Access-Control-Allow-Origin", "*");
        // 解决办法通过获取Origin请求头来动态设置
        String origin = request.getHeader("Origin");
        if (StringUtils.hasText(origin)) {
            resp.addHeader("Access-Control-Allow-Origin", origin);
        }
        // 允许带有cookie访问
        resp.addHeader("Access-Control-Allow-Credentials", "true");

        // 告诉浏览器允许跨域访问的方法
        resp.addHeader("Access-Control-Allow-Methods", "*");

        // 告诉浏览器允许带有Content-Type,header1,header2头的请求访问
        // resp.addHeader("Access-Control-Allow-Headers", "Content-Type,header1,header2");
        // 设置支持所有的自定义请求头
        String headers = request.getHeader("Access-Control-Request-Headers");
        if (StringUtils.hasText(headers)) {
            resp.addHeader("Access-Control-Allow-Headers", headers);
        }

        // 告诉浏览器缓存OPTIONS预检请求1小时,避免非简单请求每次发送预检请求,提升性能
        resp.addHeader("Access-Control-Max-Age", "3600");

        chain.doFilter(request, resp);
    }
}

方案4 Spring框架提供了跨域解决方案

spring提供了 @CrossOrigin注解用户解决跨域问题,同时支持全局配置
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/api/**")
			.allowedOrigins("http://domain2.com")
			.allowedMethods("PUT", "DELETE")
			.allowedHeaders("header1", "header2", "header3")
			.exposedHeaders("header1", "header2")
			.allowCredentials(false).maxAge(3600);
	}
}

方案5 服务端通过ngnix解决跨域问题 

location /{

            proxy_pass http://localhost:8080/;
           
            #告诉浏览器允许跨域访问的方法
            add_header Access-Control-Allow-Methods *;
            # 告诉浏览器缓存OPTIONS预检请求1小时
            add_header Access-Control-Max-Age 3600;
            #允许带有cookie访问
            add_header Access-Control-Allow-Credentials true;
            #注意 * 不能满足带有cookie的访问,Origin 必须是全匹配,这里通过变量获取
            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;
            }
        }

方案6 客户端通过nginx隐藏跨域

#转发全部以/api开头的请求到web服务器
   location  /api
   {

        proxy_pass http://127.0.0.1:8080/api;
   }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/172661.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 汉字转拼音(较完整)「建议收藏」

    汉字转拼音(较完整)「建议收藏」转至:https://www.cnblogs.com/jwfgsf/articles/1348668.htmlpublicclassPingYin{#region//gb2312中的汉字编码//01-09区为特殊符号。//16-55区为一级汉字,按拼音排序。//56-87区为二级汉字,按部首/笔画排序。//每个汉字及符号以两个字节来表示…

    2022年6月21日
    25
  • 谷歌的api_谷歌浏览器添加搜索引擎

    谷歌的api_谷歌浏览器添加搜索引擎1.搜索引擎API接口地址为https://www.proxy.ustclug.org/customsearch/v1?key={YOUR_KEY}&q={SEARCH_WORDS}&cx={YOUR_CX}&start={10}&num={10}通过谷歌可编程搜索引擎自定义个人搜索引擎,并且记住搜索引擎的CXid。创建后即可根据项目中的apiid,查询链接console.cloud.google.com根据CXid和apiid,即可调用定义好的搜索引擎

    2022年9月4日
    2
  • WinSCP连接Ubuntu拒绝访问,SSH访问状态确认

    WinSCP连接Ubuntu拒绝访问,SSH访问状态确认WinSCP连接Ubuntu拒绝访问的问题

    2022年9月15日
    0
  • 什么是低代码技术_低代码开发是什么

    什么是低代码技术_低代码开发是什么那么在后疫情时代,究竟需要什么样的新技术,才能真正解放IT生产力,加速社会数字化转型,MakeTheWorldGreatAgain?我认为是低代码(Low-Code)。

    2022年10月4日
    0
  • 反Secure Boot垄断:兼谈如何在Windows 8电脑上安装Linux

    反Secure Boot垄断:兼谈如何在Windows 8电脑上安装Linux

    2021年9月15日
    40
  • LLDP简介

    LLDP简介1.1.1LLDP产生背景目前,网络设备的种类日益繁多且各自的配置错综复杂,为了使不同厂商的设备能够在网络中相互发现并交互各自的系统及配置信息,需要有一个标准的信息交流平台。LLDP(LinkLayerDiscoveryProtocol,链路层发现协议)就是在这样的背景下产生的,它提供了一种标准的链路层发现方式,可以将本端设备的信息(包括主要能力、管理地址、设备标识、接口标识等)组织成不同的TLV(Type/Length/Value,类型/长度/值),并封装在LLDPDU(Lin…

    2022年5月28日
    88

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号