CORS 跨域解决方案

2018-07-13 admin

CORS 跨域解决方案

首先通读下 MDN 关于 CORS 的定义,了解跨域的含义及简单请求和复杂请求等的定义。文中的内容不赘述,现在说解决方案。

通过定义我们可以,简单请求与复杂请求的差别是复杂请求会自动发出一个 OPTIONS 的预检请求,当请求得到确认后,才开始真正发送请求。

综上,我们要解决两个问题:

  1. OPTIONS 请求的正确响应
  2. 跨域请求正确响应

Q1: OPTIONS 请求的正确响应

解决的方式有多种,既可以在Web Server解决,也可以在源码层解决。因为问题比较普遍,故我们选择在Web Server解决,下面我们以 Nginx 为例,说明解决方案。

假设访问的地址为 /example , Nginx 配置如下:

location /example {
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/;
  }

为了解决跨域问题,添加如下内容:

location /example {
+   if ($request_method = 'OPTIONS') {
+       add_header Access-Control-Allow-Origin *;
+       add_header Access-Control-Max-Age 1728000;
+       add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
+       add_header Access-Control-Allow-Headers  'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+       add_header Content-Type' 'text/plain; charset=utf-8';
+       add_header Content-Length 0 ;
+       return 204;
+    }

    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/;
   }

解释:

if ($request_method = 'OPTIONS') {...} 当请求方法为 OPTIONS 时:

  1. 添加允许源 Access-Control-Allow-Origin* (可根据业务需要更改)
  2. 添加缓存时长 Access-Control-Max-Age,当下次请求时,无需再发送 OPTIONS 请求
  3. 添加允许的方法,允许的首部
  4. 添加一个内容长度为0,类型为 text/plain; charset=utf-8 , 返回状态码为 204 的首部

至此,完成 OPTIONS 请求的正确响应。

Q2: 跨域请求正确响应

添加如下内容:

location /example {
   if ($request_method = 'OPTIONS') {
       add_header Access-Control-Allow-Origin *;
       add_header Access-Control-Max-Age 1728000;
       add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
       add_header Access-Control-Allow-Headers  'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
       add_header Content-Type' 'text/plain; charset=utf-8';
       add_header Content-Length 0 ;
       return 204;
    }

+   if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {
+     add_header  Access-Control-Allow-Origin $http_origin;
+     add_header  Access-Control-Allow-Credentials true;
+     add_header  Access-Control-Allow-Methods GET,POST,OPTIONS;
+     add_header  Access-Control-Expose-Headers Content-Length,Content-Range;
+   }

    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8080/;
   }

解释:

if ($http_origin ~* (https?://(.+\.)?(example\.com$))) {...}, 当 origin 为合法域名(可根据业务调整或去除合法域名验证)时:

  1. 添加允许源Access-Control-Allow-Origin$http_origin (可根据业务需要更改)
  2. 添加允许认证Access-Control-Allow-Credentialstrue ,允许接收客户端 Cookie(可根据业务需要更改。 但要注意,当设置为true时,Access-Control-Allow-Origin 不允许设置为 *)
  3. 添加允许的方法,暴露的首部

至此,完成跨域请求正确响应。

以上,是对跨域请求在Web Server的解决方案,主要是通过响应 OPTIONS 方法和添加允许源来解决。


当然,如果本地开发中,可以在利用 webpack-dev-serverproxy 选项来快速解决跨域问题: 示例如下:

// webpack.congf.js

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        pathRewrite: {'^/api' : ''}
      }
    }
  }
}

当访问地址如 /api/foo?q=bar 时,则通过代理访问的实际地址是: http://localhost:3000/foo?q=bar


CORS跨域请求并不魔幻,理解 CORS 的含义,根据规则去找方法就迎刃而解了。希望能帮助到大家。

以上。

原文链接:https://zhuanlan.zhihu.com/p/39622082

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-35910.html

文章标题:CORS 跨域解决方案

相关文章
鼠标经过子元素触发mouseout,mouseover事件的解决方案
我想实现的目标:当鼠标进入黑色框时,橙色框执行淡入动画;当黑色框范围移动的时候(即使经过粉色框,动画仍然不被触发);当鼠标移出的时候,橙色方块消失。 遇到的问题阐述:当鼠标移入黑色框的时候,橙色框执行淡入动画,但是当鼠标从黑色框经过粉色框的...
2017-03-27
详细解密jsonp跨域请求
1.什么是跨域请求: 服务器A上的一个页面,要请求服务器B上的一个处理程序,这就叫做跨域请求 本次的测试页面为: 处理程序kimhandler.ashx,如下: %@ WebHandler Language="C#" C...
2017-03-22
Bootstrap页面缩小变形的快速解决办法
bootstrap布局是应用得很广泛的一种网页布局方法,例如:我们用一种中间内容很流行的布局分布:3-6-3式布局。代码如下 <style type="text/css"> body{width:1...
2017-03-20
JavaScript汉诺塔问题解决方法
本文实例讲述了JavaScript汉诺塔问题解决方法。分享给大家供大家参考。具体实现方法如下: <script language="javascript"> var han=function (disc,s...
2017-03-22
浅析Node.js中使用依赖注入的相关问题及解决方法
最近,我转向使用依赖注入来帮助理解分离代码的简单途径,并有助测试。然而,Node.js中的模块依赖Node提供的系统API,这很难判断私有依赖被恰当的使用。一般的依赖注入很难在这种情况下使用,但现在不要放弃希望。 requireCauses...
2017-03-24
javascript 中设置window.location.href跳转无效问题解决办法
javascript 中设置window.location.href跳转无效问题解决办法 问题情况 JS中设置window.location.href跳转无效 代码如下: <script type="text/ja...
2017-03-17
实现placeholder效果的方案汇总
placeholder是html5<input>的一个属性,它提供可描述输入字段预期值的提示信息(hint), 该提示会在输入字段为空时显示。高端浏览器支持此属性(ie10/11在获得焦点时文字消失),ie6/7/8/9则不支持...
2017-03-24
使用微信内嵌H5网页解决JS倒计时失效问题
项目要求:将H5商城页面嵌套到公司微信公众号里 项目本身的开发跟移动端网页并无太多差异,只是这昨天遇到一个问题,说是棘手,到也简单。 用户下单后,在选择支付方式页面,有个倒计时的逻辑(从下单时开始计算,24小时后未支付,会有ws自动取消这个...
2017-03-10
利用js判断手机是否安装某个app的多种方案
前言 大家在日常开发的时候,经常会遇到这样的需求,通过检测手机,如果本地安装了app那么直接打开,否则苹果要跳转到app-store,安卓则要跳到对应的市场,下面来给大家介绍几种解决的方案。 解决方案 一 //html代...
2017-02-15
使用Promise链式调用解决多个异步回调的问题
介绍 所谓Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。 缺少场景支撑,对于新手而言,很难理解Promise的意义。 在《你不知道的JavaScript中》有个场景介绍得很形象: 我走到...
2017-03-09
回到顶部