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
详解vuelidate 对于vueJs2.0的验证解决方案
介绍 在后端项目里 比如我们的Laravel框架 对于表单验证有自己的一套validation机制 他将验证集成在FormRequest 我们只需要在我们的方法中依赖注入我们自己实例化后的验证类 当然也可以直接去在方法里去验证表单数据 而在...
2017-03-13
JavaScript汉诺塔问题解决方法
本文实例讲述了JavaScript汉诺塔问题解决方法。分享给大家供大家参考。具体实现方法如下: <script language="javascript"> var han=function (disc,s...
2017-03-22
javascript 中设置window.location.href跳转无效问题解决办法
javascript 中设置window.location.href跳转无效问题解决办法 问题情况 JS中设置window.location.href跳转无效 代码如下: <script type="text/ja...
2017-03-17
浅析Node.js中使用依赖注入的相关问题及解决方法
最近,我转向使用依赖注入来帮助理解分离代码的简单途径,并有助测试。然而,Node.js中的模块依赖Node提供的系统API,这很难判断私有依赖被恰当的使用。一般的依赖注入很难在这种情况下使用,但现在不要放弃希望。 requireCauses...
2017-03-24
webpack 换肤功能多主题/配色样式打包解决方案
色阶 本文主要详细介绍了,如何使用 webpack,打包多套不同主题的解决方案以及实践中所遇到的问题。 <a id=“more”></a> 起因 首先,简单的介绍一下什么是多主题,所谓多套主题/配色,就是我们很常见...
2018-04-23
实现placeholder效果的方案汇总
placeholder是html5<input>的一个属性,它提供可描述输入字段预期值的提示信息(hint), 该提示会在输入字段为空时显示。高端浏览器支持此属性(ie10/11在获得焦点时文字消失),ie6/7/8/9则不支持...
2017-03-24
IoT实时数据可视化方案(进阶版):Worldmap Panel使用详解及使用Node-RED进行流程管理
Chap.1 万万没想到,我这一世英名葬送在了地图坑里 继上次搭建完框架得到了个粗糙的demo以后,我天真地以为我离真理的距离简直就只有一步之遥了。基本的图形组件试了个遍没什么。   想着我还有些模拟的地理数据没有做可视化,数据信息的内容放...
2018-01-03
回到顶部