(function () {

  'use strict';

  var assign = require('object-assign');
var vary = require('vary'); var defaults = {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
preflightContinue: false,
optionsSuccessStatus: 204
}; function isString(s) {
return typeof s === 'string' || s instanceof String;
} function isOriginAllowed(origin, allowedOrigin) {
// 多次递归返回一个地址
if (Array.isArray(allowedOrigin)) {
for (var i = 0; i < allowedOrigin.length; ++i) {
if (isOriginAllowed(origin, allowedOrigin[i])) {
return true;
}
}
return false;
// 在白名单里面就通过
} else if (isString(allowedOrigin)) {
return origin === allowedOrigin;
// 正则匹配
} else if (allowedOrigin instanceof RegExp) {
return allowedOrigin.test(origin);
} else {
return !!allowedOrigin;
}
} function configureOrigin(options, req) {
var requestOrigin = req.headers.origin,
headers = [],
isAllowed;
// 默认所有域名都可以使用
if (!options.origin || options.origin === '*') {
// allow any origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: '*'
}]);
// 固定的一个域名
} else if (isString(options.origin)) {
// fixed origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: options.origin
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
} else {
// 这里通过白名单列表
isAllowed = isOriginAllowed(requestOrigin, options.origin);
// reflect origin
headers.push([{
key: 'Access-Control-Allow-Origin',
value: isAllowed ? requestOrigin : false
}]);
headers.push([{
key: 'Vary',
value: 'Origin'
}]);
} return headers;
} // 允许的方法
function configureMethods(options) {
var methods = options.methods;
if (methods.join) {
methods = options.methods.join(','); // .methods is an array, so turn it into a string
}
return {
key: 'Access-Control-Allow-Methods',
value: methods
};
} function configureCredentials(options) {
// 是否带cookies
if (options.credentials === true) {
return {
key: 'Access-Control-Allow-Credentials',
value: 'true'
};
}
return null;
} function configureAllowedHeaders(options, req) {
var allowedHeaders = options.allowedHeaders || options.headers;
var headers = []; // 如果没有请求头, 那么指定请求头
if (!allowedHeaders) {
allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers
headers.push([{
key: 'Vary',
value: 'Access-Control-Request-Headers'
}]);
} else if (allowedHeaders.join) {
allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string
}
if (allowedHeaders && allowedHeaders.length) {
headers.push([{
key: 'Access-Control-Allow-Headers',
value: allowedHeaders
}]);
} return headers;
} // 该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
// 如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
// https://github.com/expressjs/cors#configuration-options
function configureExposedHeaders(options) {
var headers = options.exposedHeaders;
if (!headers) {
return null;
} else if (headers.join) {
headers = headers.join(','); // .headers is an array, so turn it into a string
}
if (headers && headers.length) {
return {
key: 'Access-Control-Expose-Headers',
value: headers
};
}
return null;
} // 在此时间内不需要发出预检查请求
function configureMaxAge(options) {
var maxAge = options.maxAge && options.maxAge.toString();
if (maxAge && maxAge.length) {
return {
key: 'Access-Control-Max-Age',
value: maxAge
};
}
return null;
} // 发送响应头
function applyHeaders(headers, res) {
for (var i = 0, n = headers.length; i < n; i++) {
var header = headers[i];
if (header) {
if (Array.isArray(header)) {
applyHeaders(header, res);
} else if (header.key === 'Vary' && header.value) {
vary(res, header.value);
} else if (header.value) {
res.setHeader(header.key, header.value);
}
}
}
} function cors(options, req, res, next) {
var headers = [],
method = req.method && req.method.toUpperCase && req.method.toUpperCase();
// 嗅探请求 如果是非简单请求,那么会先发送这个
// 关于简单请求和非简单请求
// 这里写的很详细 http://www.lcode.cc/2016/12/06/cors-explain.html
if (method === 'OPTIONS') {
// preflight
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureMethods(options, req));
headers.push(configureAllowedHeaders(options, req));
headers.push(configureMaxAge(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res); // 兼容一波zz浏览器
if (options.preflightContinue ) {
next();
} else {
// Safari (and potentially other browsers) need content-length 0,
// for 204 or they just hang waiting for a body
res.statusCode = options.optionsSuccessStatus || defaults.optionsSuccessStatus;
res.setHeader('Content-Length', '0');
res.end();
}
} else {
// 返回正常的结果
// actual response
headers.push(configureOrigin(options, req));
headers.push(configureCredentials(options, req));
headers.push(configureExposedHeaders(options, req));
applyHeaders(headers, res);
next();
}
} function middlewareWrapper(o) {
// 设置回调函数
// if options are static (either via defaults or custom options passed in), wrap in a function
var optionsCallback = null;
if (typeof o === 'function') {
optionsCallback = o;
} else {
optionsCallback = function (req, cb) {
cb(null, o);
};
}
// 使用到了闭包
return function corsMiddleware(req, res, next) {
optionsCallback(req, function (err, options) {
if (err) {
// 出错了直接进入下一个中间件
next(err);
} else {
var corsOptions = assign({}, defaults, options);
var originCallback = null;
// 通过传参数进来可以动态使用cors。
// 见文档 https://github.com/expressjs/cors#configuring-cors-w-dynamic-origin
if (corsOptions.origin && typeof corsOptions.origin === 'function') {
originCallback = corsOptions.origin;
} else if (corsOptions.origin) {
originCallback = function (origin, cb) {
cb(null, corsOptions.origin);
};
} if (originCallback) {
// 用来设置白名单
originCallback(req.headers.origin, function (err2, origin) {
if (err2 || !origin) {
next(err2);
} else {
corsOptions.origin = origin;
cors(corsOptions, req, res, next);
}
});
} else {
next();
}
}
});
};
} // can pass either an options hash, an options delegate, or nothing
module.exports = middlewareWrapper; }());

  

解析node-cors模块的更多相关文章

  1. Node.js-Events 模块总结与源码解析

    Events 描述 大多数 Node.js API 采用异步事件驱动架构,这些对象都是EventEmitter类的实例(Emitter),通过触发命名事件(eventName or type)来调用函 ...

  2. 深入浅出node(2) 模块机制

    这部分主要总结深入浅出Node.js的第二章 一)CommonJs 1.1CommonJs模块定义 二)Node的模块实现 2.1模块分类 2.2 路径分析和文件定位 2.2.1 路径分析 2.2.2 ...

  3. Node.js模块

    每一个Node.js都是一个Node.js模块,包括JavaScript文件(.js).JSON文本文件(.json)和二进制模块文件(.node). mymodul.js function Hell ...

  4. python 解析XML python模块xml.dom解析xml实例代码

    分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...

  5. Node.js 模块

    稳定性: 5 - 锁定 Node 有简单的模块加载系统.在 Node 里,文件和模块是一一对应的.下面例子里,foo.js 加载同一个文件夹里的 circle.js 模块. foo.js 内容: va ...

  6. node基础—模块系统

    模块的概念 为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块加载系统. 在 Node.js 中,文件和模块是一一对应的(每个文件被视为一个独立的模块),换言之,一个 Node ...

  7. 10、Node.js模块系统

    ##################################################################################介绍Node.js模块系统为了让No ...

  8. 如何发布一个自定义Node.js模块到NPM(详细步骤)

    咱们闲话不多说,直接开始! 由于我从没有使用过MAC,所以我不保证本文中介绍的操作与MAC一致. 文章开始我先假定各位已经在window全局安装了Node.js,下面开始进行详细步骤介绍: 本文本着, ...

  9. 编写原生Node.js模块

    导语:当Javascript的性能需要优化,或者需要增强Javascript能力的时候,就需要依赖native模块来实现了. 应用场景 日常工作中,我们经常需要将原生的Node.js模块做为依赖并在项 ...

  10. 编写原生的Node.js模块

    导语:当Javascript的性能遭遇瓶颈,或者需要增强Javascript能力的时候,就需要依赖native模块来实现了. 应用场景 日常工作中,我们经常需要将原生的Node.js模块做为依赖并在项 ...

随机推荐

  1. 前端学习:CSS的学习总结(图解)

    前端学习:CSS的学习总结(图解) CSS代码笔记 CSS简介 css的引入方式和书写规范 CSS选择器 CSS属性 CSS盒子模型 CSS的定位

  2. Git 核心概念

    原文链接 Git的核心概念 聪聪的个人网站 本文不是Git使用教学篇,而是偏向理论方面,旨在更加深刻的理解Git,这样才能更好的使用它,让工具成为我们得力的助手. 版本控制系统 Git 是目前世界上最 ...

  3. excel中快捷计算单一列中的所有的值

    excel中快捷计算单一列中的所有的值 比如B列中所有的值 =SUM(B1:B100) 计算B列第一行到第100行的值 又学了一招  如果想统计B列所有的值 可以用 =SUM(B:B)

  4. Linux 笔记 - 第二十三章 MySQL 主从复制配置

    一.前言 MySQL Replication,也被称为主从复制.AB 复制.简单来说就是 A 和 B 两台服务器做主从后,在 A 服务器上写入数据,B 服务器上也会跟着写入输入,两者之间的数据是实时同 ...

  5. 匿名方法是怎样演变到Lambda表达试过程

    一.  "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda ab ...

  6. sql server: 数据库备份时出现-operating-system-error-5拒绝访问

    本文转自:https://blog.csdn.net/ibsfn/article/details/80770855 sql-server 数据库备份时出现-operating-system-error ...

  7. redis集群cluster简单设置

    环境: 这里参考官方使用一台服务器:Centos 7  redis-5.0.4    192.168.10.10 redis集群cluster最少要3个主节点,所以本次需要创建6个实例:3个主节点,3 ...

  8. Java生成前三位是字母循环的字典

    title: Java生成前三位是字母循环的字典 date: 2018-08-17 18:52:22 tags: Java --- 最近要破解一个秘密,还好这个密码是有线索的,已知密码的前三位是三个字 ...

  9. Asp.Net SignalR 使用记录 技术回炉重造-总纲 动态类型dynamic转换为特定类型T的方案 通过对象方法获取委托_C#反射获取委托_ .net core入门-跨域访问配置

    Asp.Net SignalR 使用记录   工作上遇到一个推送消息的功能的实现.本着面向百度编程的思想.网上百度了一大堆.主要的实现方式是原生的WebSocket,和SignalR,再次写一个关于A ...

  10. (原)在anaconda3+ubuntu16.04中编译Pose flow中的deepmatching动态库

    转载请注明出处: https://www.cnblogs.com/darkknightzh/p/11285239.html 参考网址: https://github.com/YuliangXiu/Po ...