首页
Angular.js源码分析之ngrepeat
发表于2015年11月03日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
在angular中一旦涉及到列表类的往往就轮到ng-repeat
这个指令出马了,其实就是循环数组或者对象,然后渲染得到内容。核心就是利用$transclude
,他可以被调用多次,而且会自动创建单独的scope,用$transclude
来做再好不过了。
首先来看下其源码:
var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
var NG_REMOVED = '$$NG_REMOVED';
var ngRepeatMinErr = minErr('ngRepeat');
var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
// 增加额外的一些属性值
scope[valueIdentifier] = value;
if (keyIdentifier) scope[keyIdentifier] = key;
scope.$index = index;
scope.$first = (index === 0);
scope.$last = (index === (arrayLength - 1));
scope.$middle = !(scope.$first || scope.$last);
// jshint bitwise: false
scope.$odd = !(scope.$even = (index&1) === 0);
// jshint bitwise: true
};
var getBlockStart = function(block) {
return block.clone[0];
};
var getBlockEnd = function(block) {
return block.clone[block.clone.length - 1];
};
return {
restrict: 'A',
multiElement: true, // 跨域多个元素可以
transclude: 'element',
priority: 1000,
terminal: true,
$$tlb: true,
compile: function ngRepeatCompile($element, $attr) {
// ngRepeat的表达式
var expression = $attr.ngRepeat;
var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
// 省略
return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
if (trackByExpGetter) {
trackByIdExpFn = function(key, value, index) {
// assign key, value, and $index to the locals so that they can be used in hash functions
if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
hashFnLocals[valueIdentifier] = value;
hashFnLocals.$index = index;
return trackByExpGetter($scope, hashFnLocals);
};
}
var lastBlockMap = createMap();
// 监控集合属性变化
$scope.$watchCollection(rhs, function ngRepeatAction(collection) {
var index, length,
previousNode = $element[0], // 应该插入到previousNode节点之后
nextBlockMap = createMap(),
collectionLength,
key, value, // key/value of iteration
trackById,
trackByIdFn,
collectionKeys,
block, // last object information {scope, element, id}
nextBlockOrder,
elementsToRemove;
if (aliasAs) {
// 如果有 as 语法
$scope[aliasAs] = collection;
}
if (isArrayLike(collection)) {
// 类似于数组
collectionKeys = collection;
trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
} else {
// 对象 但是要得到key组成的数组
trackByIdFn = trackByIdExpFn || trackByIdObjFn;
// if object, extract keys, in enumeration order, unsorted
collectionKeys = [];
for (var itemKey in collection) {
if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
collectionKeys.push(itemKey);
}
}
}
collectionLength = collectionKeys.length;
nextBlockOrder = new Array(collectionLength);
// 定位现有的那些项
for (index = 0; index < collectionLength; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
trackById = trackByIdFn(key, value, index);
if (lastBlockMap[trackById]) {
// 如果存在就利用
block = lastBlockMap[trackById];
delete lastBlockMap[trackById];
nextBlockMap[trackById] = block;
nextBlockOrder[index] = block;
} else if (nextBlockMap[trackById]) {
// 现在的里边存在 说明 key 存在重复 报错
forEach(nextBlockOrder, function(block) {
if (block && block.scope) lastBlockMap[block.id] = block;
});
throw ngRepeatMinErr('dupes',
"Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
expression, trackById, value);
} else {
// 全新的项
nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
nextBlockMap[trackById] = true;
}
}
// 移除剩余的哪些项 在新的里边不存在
for (var blockKey in lastBlockMap) {
block = lastBlockMap[blockKey];
elementsToRemove = getBlockNodes(block.clone);
$animate.leave(elementsToRemove);
if (elementsToRemove[0].parentNode) {
// if the element was not removed yet because of pending animation, mark it as deleted
// so that we can ignore it later
for (index = 0, length = elementsToRemove.length; index < length; index++) {
elementsToRemove[index][NG_REMOVED] = true;
}
}
// 销毁
block.scope.$destroy();
}
// 循环构建内容
for (index = 0; index < collectionLength; index++) {
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
block = nextBlockOrder[index];
if (block.scope) {
// 以前就存在的
nextNode = previousNode;
// skip nodes that are already pending removal via leave animation
do {
nextNode = nextNode.nextSibling;
} while (nextNode && nextNode[NG_REMOVED]);
if (getBlockStart(block) != nextNode) {
// 移除掉
$animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
}
previousNode = getBlockEnd(block);
// 更新scope
updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
} else {
// 新的项 通过$transclude得到新的copy内容
$transclude(function ngRepeatTransclude(clone, scope) {
block.scope = scope;
// http://jsperf.com/clone-vs-createcomment
var endNode = ngRepeatEndComment.cloneNode(false);
clone[clone.length++] = endNode;
// 插入元素
$animate.enter(clone, null, jqLite(previousNode));
previousNode = endNode;
// 保留clone节点
block.clone = clone;
nextBlockMap[block.id] = block;
// 更新scope
updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
});
}
}
lastBlockMap = nextBlockMap;
});
};
}
};
}];
可以看出上边的基本过程,得到repeat的表达式,然后进行简单的解析,之后就返回了link函数;在link函数中主要是watch了集合的变化,发生改变时,如果有新增的项,那么就通过$transclude
得到新的clone内容,然后插入即可;如果是删除的话,直接也是移除了;而对于已存在的要去更新对应的scope信息。
核心还是利用$transclude
会每次克隆一份原始内容,而且本身会创建scope,所以就最大效用的发挥了其作用。
Angular.js源码分析之ngif
发表于2015年10月27日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
在angular中有两个内置的指令ng-if
和ng-repeat
是比较特殊的,特殊之处在于他们创建指令时候多了一个内置参数配置:$$tlb
。ng-if
相对ng-repeat
逻辑则更加简单,分析起来也就更容易。所以这里就来分析分析ng-if
指令,目的是不仅要知道了ng-if
指令的逻辑,也要知道这个参数为啥会存在。
先来看下源码:
var ngIfDirective = ['$animate', function($animate) {
return {
multiElement: true,
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
$$tlb: true, // 这个特殊的参数
link: function($scope, $element, $attr, ctrl, $transclude) {
var block, childScope, previousElements;
// 检测值变化
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
if (value) {
// true就是要显示
if (!childScope) {
// 依旧是调用$transclude
$transclude(function(clone, newScope) {
childScope = newScope;
// 插入注释元素
clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
// 保留引用
block = {
clone: clone
};
$animate.enter(clone, $element.parent(), $element);
});
}
} else {
// 隐藏
// 有的话就销毁 且动画移除
if (previousElements) {
previousElements.remove();
previousElements = null;
}
if (childScope) {
childScope.$destroy();
childScope = null;
}
if (block) {
previousElements = getBlockNodes(block.clone);
$animate.leave(previousElements).then(function() {
previousElements = null;
});
block = null;
}
}
});
}
};
}];
从上边代码可以看出其基本逻辑还是很简单的,但是不明白的是这个私有的设置参数$$tlb
到底是用来干嘛的,有啥用处吗?是为了解决什么样的问题的(当然不建议开发者使用)?
我觉得不如首先来看没有这个配置会出现什么问题呢?做一个实验,把ngIfDirective
的源码中的$$tlb
去掉,然后来一个简单的demo,一探究竟。
Angular.js源码分析之ngcontroller
发表于2015年10月26日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
在angular中用的最多的指令可能就是ng-controller
,下边就一起来分析下这个指令。
先来看下源码:
var ngControllerDirective = [function() {
return {
restrict: 'A',
scope: true,
controller: '@',
priority: 500
};
}];
可以看到代码是很简单的,这里可能唯一需要注意的细节就是controller: '@'
这个是神马意思?其实这个逻辑在之前分析link中分析nodeLinkFn
的时候其中有setupControllers
这个函数,他有这样的逻辑:
// 在controller中可以注入的东西
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: transcludeFn
};
// 省略
var controller = directive.controller;
if (controller == '@') {
// ngController设置的controller的值是@
// 需要找回属性中的该值
controller = attrs[directive.name];
}
// 调用$controller服务 但是 是延迟的
var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
所以上边的指令中controller
的意思就很明显了,就是取得其属性(ng-controller
)值。但是后边的一行逻辑值得我们注意,那就是$controller
服务。
Angular.js源码分析之nginclude
发表于2015年10月25日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
还记得在源码分析之compile中在分析$CompileProvider
的实例directive
(也就是module实例可以用来自定义指令的directive
)方法的时候,里边说到对于每自定义一个指令其实都会有对应的Provider
存在,这里再次看下那部分代码:
/**
* 注册新的指令
*/
this.directive = function registerDirective(name, directiveFactory) {
assertNotHasOwnProperty(name, 'directive');
if (isString(name)) {
// key value 形式
assertValidDirectiveName(name);
assertArg(directiveFactory, 'directiveFactory');
if (!hasDirectives.hasOwnProperty(name)) {
// 还没有name的Directive工厂
hasDirectives[name] = [];
// 加后缀Directive
$provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
function($injector, $exceptionHandler) {
// 此时使用的时候
// 取得所有的directiveFactory然后执行
// 得到的就是要如何构建指令的对象(指令对象)
var directives = [];
forEach(hasDirectives[name], function(directiveFactory, index) {
try {
var directive = $injector.invoke(directiveFactory);
if (isFunction(directive)) {
directive = { compile: valueFn(directive) };
} else if (!directive.compile && directive.link) {
directive.compile = valueFn(directive.link);
}
// 指令对象的配置属性们
directive.priority = directive.priority || 0;
directive.index = index;
directive.name = directive.name || name;
directive.require = directive.require || (directive.controller && directive.name);
directive.restrict = directive.restrict || 'EA';
// 解析scope(bindToController)绑定
var bindings = directive.$$bindings =
parseDirectiveBindings(directive, directive.name);
if (isObject(bindings.isolateScope)) {
// 独立scope对象
directive.$$isolateBindings = bindings.isolateScope;
}
// 指定directive的$$moduleName
// 也就是在moduleInstance对象上暴露directive的时候使用的是
// invokeLaterAndSetModuleName 给directiveFactory赋值了$$moduleName
directive.$$moduleName = directiveFactory.$$moduleName;
directives.push(directive);
} catch (e) {
$exceptionHandler(e);
}
});
return directives;
}]);
}
// 添加
hasDirectives[name].push(directiveFactory);
} else {
// 批量注册 指令
forEach(name, reverseParams(registerDirective));
}
return this;
};
在那篇文章中有这样说:
从上边可以看出在调用
directive
的时候其实是会创建一个以name+Suffix
为名的service的(通过$provide.factory
的方法),也就意味着同一个名字的指令可以有多个directiveFactory
的,也就说我们可以一直增强同一个指令。
而在angular中一个指令被定义多次的就有这样的一个指令ngInclude
,也就是本篇要分析的重点。
Angular.js源码分析之link
发表于2015年10月24日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
在angular初始化的最后阶段有这样的一段代码:
compile(element)(scope);
上一篇大概分析了下compile,那么这次继续分析下一步也就是调用传入scope,其实这一步也就是所谓的link。
回顾上篇中说了compile
的返回的结果是一个publicLinkFn
函数,然后link阶段其实也就是调用这个函数了:
return function publicLinkFn(scope, cloneConnectFn, options) {
assertArg(scope, 'scope');
options = options || {};
var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
transcludeControllers = options.transcludeControllers,
futureParentElement = options.futureParentElement;
// When `parentBoundTranscludeFn` is passed, it is a
// `controllersBoundTransclude` function (it was previously passed
// as `transclude` to directive.link) so we must unwrap it to get
// its `boundTranscludeFn`
if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
}
if (!namespace) {
namespace = detectNamespaceForChildElements(futureParentElement);
}
var $linkNode;
if (namespace !== 'html') {
// When using a directive with replace:true and templateUrl the $compileNodes
// (or a child element inside of them)
// might change, so we need to recreate the namespace adapted compileNodes
// for call to the link function.
// Note: This will already clone the nodes...
$linkNode = jqLite(
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
);
} else if (cloneConnectFn) {
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
// 因为在处理transclude的时候也会compile
// 而返回的那个函数transcludeFn被调用的时候 会传入第二个参数
// 因为transcludeFn可能会被调用多次 所以这里需要clone一份
$linkNode = JQLitePrototype.clone.call($compileNodes);
} else {
$linkNode = $compileNodes;
}
if (transcludeControllers) {
for (var controllerName in transcludeControllers) {
$linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
}
}
compile.$$addScopeInfo($linkNode, scope);
// 其实就是transclude传入的函数
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
// 执行compositeLinkFn函数 里边会执行所有的link函数
// link 到scope
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
return $linkNode;
};
可以看到调用了在上一篇compile中compileNodes
返回的处理所有节点的link函数,来看下具体逻辑:
Angular.js源码分析之compile编译
发表于2015年10月23日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
上一篇提到了angular中编译compile部分,下边就来一起看看其详细的实现过程。
首先来找找$compile
服务这个是在什么时候定义的,找到核心模块ng
中一段代码:
angularModule('ng', ['ngLocale'], ['$provide',
function ngModule($provide) {
// 省略
// 创建$compile的$CompileProvider
$provide.provider('$compile', $CompileProvider)
.directive({
a: htmlAnchorDirective,
input: inputDirective,
//省略
})
// 省略
}
])
所以说这里要分析的是$CompileProvider
以及为啥能直接链式调用directive
的问题(注意到了吗?$provide
是没有directive
方法的,所以注定是$provide.provider()
的返回值有directive
方法)。
首先来看下$CompileProvider
的代码:
/**
* 核心 compile
*/
$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {}, // 保存所有的指令
Suffix = 'Directive',
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
// The assumption is that future DOM event attribute names will begin with
// 'on' and be composed of only English letters.
var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
// 省略
this.directive = function registerDirective(name, directiveFactory) {
// 省略
};
// 省略
var debugInfoEnabled = true;
this.debugInfoEnabled = function(enabled) {
if (isDefined(enabled)) {
debugInfoEnabled = enabled;
return this;
}
return debugInfoEnabled;
};
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
'$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
// 省略
}];
}
Angular.js源码分析之注入器
发表于2015年10月22日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
上一篇主要分析了整体的执行流程,最后说到了要执行注入器部分了,下边就一起来看看angular强大的依赖注入机制是怎样一回事。
注入器
执行过程的那部分代码是这样子的:
// 创建注入器
// 隐藏了注入机制
// 详见createInjector函数
var injector = createInjector(modules, config.strictDi);
// 注入这几个服务执行bootstrapApply
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
// 进入ng环境(上下文)执行
element.data('$injector', injector);
// compile 核心
// compile返回一个publicLink函数
// 然后传入scope直接执行
// 这个scope也就是rootScope
compile(element)(scope);
});
}]
);
首先就要看看createInjector
是个什么鬼?
// 创建注入器实例
function createInjector(modulesToLoad, strictDi) {
strictDi = (strictDi === true);
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap([], true),
providerCache = {
$provide: {// $provide服务
provider: supportObject(provider),
factory: supportObject(factory),
service: supportObject(service),
value: supportObject(value),
constant: supportObject(constant),
decorator: decorator
}
},
// $injector服务
providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})),
// provider实例(调用$get)缓存
instanceCache = {},
instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
// 加载执行module
// loadModules得到的是所有的runBlocks
// 然后执行runBlocks中内容
forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
return instanceInjector;
// 省略一些代码 看后续分析
}
createInjector.$$annotate = annotate;
从上往下看,首先看providerCache
对象有$provide
属性,值为对象,提供了provider,factory,service
、value,constant
以及decorator
这些方法,很明显猜到了这里就是angular的$provide
服务的实现部分。
supportObject
这里使用了supportObject
方法,先看看如何实现的:
// supportObject(function(key, val) {})
// 支持对象式传参调用
// 也就是在外边可以类似这样使用
// module.provider({
// aDirective: function() {}
// bDirective: function() {}
// })
function supportObject(delegate) {
return function(key, value) {
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
};
}
其实就是提供了对象式便捷的调用方式。
Angular.js源码分析之scope作用域
发表于2015年10月22日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
上一篇在最后提到了依赖项中的$rootScope
,那部分代码是这样的:
// 创建注入器
// 隐藏了注入机制
// 详见createInjector函数
var injector = createInjector(modules, config.strictDi);
// 注入这几个服务执行bootstrapApply
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
function bootstrapApply(scope, element, compile, injector) {
scope.$apply(function() {
// 进入ng环境(上下文)执行
element.data('$injector', injector);
// compile 核心
// compile返回一个publicLink函数
// 然后传入scope直接执行
// 这个scope也就是rootScope
compile(element)(scope);
});
}]
);
本篇就来分析下这个$rootScope
。首先他可以被注入,那他是在什么地方加入到注入器缓存中的呢?细心的可能以及发现,在核心模块ng
中,有一段这样的代码:
// 继续一堆的provider
$provide.provider({
$anchorScroll: $AnchorScrollProvider,
// 省略
$controller: $ControllerProvider,
// 省略
$rootScope: $RootScopeProvider,
// 省略
});
这里就看到了原来核心是$RootScopeProvider
这个玩意搞得。
Angular.js源码分析之开篇 执行流程
发表于2015年10月21日 分类: js 标签: angular angular.js 源码分析 angular源码分析 js
从本篇开始主要来分析下angular.js(v1.4.7)的源码,这是第一篇,先看最基础的,整个angular的初始化过程是什么样的。
结构
首先看代码最后有这样的代码:
// 真正的开始执行部分
//try to bind to jquery now so that one can write jqLite(document).ready()
//but we will rebind on bootstrap again.
bindJQuery();
publishExternalAPI(angular);
angular.module("ngLocale", [], ["$provide", function($provide) {
// 代码
}]);
jqLite(document).ready(function() {
angularInit(document, bootstrap);
});
这个过程很明显,也就是首先执行bindJQuery
,然后再调用publishExternalAPI
,在页面load之后初始化angular,也就是angularInit(document, bootstrap)
。所以说源码分析也会按照这个顺序进行。
bindJQuery
从名字就可以看出,主要是绑定jQuery
的,这是因为在angular中还有一个实现了部分jQuery
功能的JQLite
,如果判断了jQuery
是存在的,那么angular.element
就直接赋值为jQuery
了,否则就为angular自身实现的JQLite
,下边看一下带分析的代码:
常用的nginx配置
发表于2015年09月06日 分类: server 标签: nginx server
前言
虽然说作为一个前端攻城师一般情况下是不会担心nginx的相关配置的,如果有运维同学的话,一般是找他们帮忙搞定这些事情的。但是小一点的公司的话可能就根本没有运维了,这时候我们就需要“自己动手,丰衣足食”了!
nginx简介
Nginx(发音同engine x)是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件(IMAP/POP3)代理服务器。由于其各种优势各种好(自行了解),所以很热很火🔥,基本上大大小小的公司都在使用了。
以前的前端可能不会涉及到这方面,但是由于node.js火爆之后,前端以及向所谓的“全栈”方向转移了,然后基于node.js的各种工程、工具也是越来越多。这时候前端需要的越来越多了,而nginx似乎成为了“刚需”(对自己而言),虽然不需要深入的了解nginx什么原理啊什么机制啊,但是最基础的还是需要的,最起码最起码会做一些基本的配置,满足自己的日常需要。
基础配置
首先,最基础的莫过于配置一个server,然后指向自己项目的根目录,以便能通过域名或者ip访问。下边看一个最基础版本的开发环境配置:
# nginx.conf
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
autoindex on; #文件列表
autoindex_exact_size off;
autoindex_localtime on;
# 开启ssi支持,默认是off
ssi on;
# 默认值是off,开启后在处理SSI文件出错时不输出错误提示:”[an error occurred while processing the directive] ”
ssi_silent_errors on;
# 默认是text/html,如果需要shtml支持,则需要设置:ssi_types text/shtml
ssi_types text/shtml;
expires -1;
if_modified_since off;
add_header Last-Modified "";
add_header Etag "";
add_header Access-Control-Allow-Origin *;# 允许任何域
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
server {
listen 80;
server_name localhost;
#access_log logs/host.access.log main;
location / {
root /git/;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 80;
server_name fed.com;
location / {
root /git/fed/;
}
}
}