AngularJs版本升级项目build后报错Error: [$injector:unpr] Unknown provider: e

mikel阅读(1565)

错误提示:

Uncaught Error: [$injector:modulerr] Failed to instantiate module mulan due to:
Error: [$injector:modulerr] Failed to instantiate module login due to:
Error: [$injector:unpr] Unknown provider: e

原因是因为AngularJs升级了,现有项目是meteor的build后提示这个错误,是因为angular声明module的时候需要用array数组声明$stateProvider,这样build后就能初始化module了

修改方法:

报错代码:

export default angular.module(‘member’, [
angularMeteor,
uiRouter,
‘header_search’,
])
.config(function ($stateProvider) { //这么声明老版本的支持,新版本不支持了
‘ngInject’;

。。。。

});

修改后的代码:

export default angular.module(‘member’, [
angularMeteor,
uiRouter,
‘header_search’,
])
.config([‘$stateProvider’,function ($stateProvider) {
‘ngInject’;

。。。。

]});

引申问题:Controller的声明也需要按数组式声明,官方文档参考:

https://docs.angularjs.org/guide/di#dependency-annotation

Using Dependency Injection

Dependency Injection is pervasive throughout AngularJS. You can use it when defining components or when providing run and config blocks for a module.

  • Servicesdirectivesfilters, and animations are defined by an injectable factory method or constructor function, and can be injected with “services”, “values”, and “constants” as dependencies.
  • Controllers are defined by a constructor function, which can be injected with any of the “service” and “value” as dependencies, but they can also be provided with “special dependencies”. See Controllers below for a list of these special dependencies.
  • The run method accepts a function, which can be injected with “services”, “values” and, “constants” as dependencies. Note that you cannot inject “providers” into run blocks.
  • The config method accepts a function, which can be injected with “providers” and “constants” as dependencies. Note that you cannot inject “services” or “values” into configuration.
  • The provider method can only be injected with other “providers”. However, only those that have been registered beforehand can be injected. This is different from services, where the order of registration does not matter.

See Modules for more details about run and config blocks and Providers for more information about the different provider types.

Factory Methods

The way you define a directive, service, or filter is with a factory function. The factory methods are registered with modules. The recommended way of declaring factories is:

angular.module('myModule', [])
.factory('serviceId', ['depService', function(depService) {
  // ...
}])
.directive('directiveName', ['depService', function(depService) {
  // ...
}])
.filter('filterName', ['depService', function(depService) {
  // ...
}]);

Module Methods

We can specify functions to run at configuration and run time for a module by calling the config and run methods. These functions are injectable with dependencies just like the factory functions above.

angular.module('myModule', [])
.config(['depProvider', function(depProvider) {
  // ...
}])
.run(['depService', function(depService) {
  // ...
}]);

Controllers

Controllers are “classes” or “constructor functions” that are responsible for providing the application behavior that supports the declarative markup in the template. The recommended way of declaring Controllers is using the array notation:

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
}]);

Unlike services, there can be many instances of the same type of controller in an application.

Moreover, additional dependencies are made available to Controllers:

  • $scope: Controllers are associated with an element in the DOM and so are provided with access to the scope. Other components (like services) only have access to the $rootScope service.
  • resolves: If a controller is instantiated as part of a route, then any values that are resolved as part of the route are made available for injection into the controller.

Dependency Annotation

AngularJS invokes certain functions (like service factories and controllers) via the injector. You need to annotate these functions so that the injector knows what services to inject into the function. There are three ways of annotating your code with service name information:

  • Using the inline array annotation (preferred)
  • Using the $inject property annotation
  • Implicitly from the function parameter names (has caveats)

Inline Array Annotation

This is the preferred way to annotate application components. This is how the examples in the documentation are written.

For example:

someModule.controller('MyController', ['$scope', 'greeter', function($scope, greeter) {
  // ...
}]);

Here we pass an array whose elements consist of a list of strings (the names of the dependencies) followed by the function itself.

When using this type of annotation, take care to keep the annotation array in sync with the parameters in the function declaration.

$inject Property Annotation

To allow the minifiers to rename the function parameters and still be able to inject the right services, the function needs to be annotated with the $inject property. The $inject property is an array of service names to inject.

var MyController = function($scope, greeter) {
  // ...
}
MyController.$inject = ['$scope', 'greeter'];
someModule.controller('MyController', MyController);

In this scenario the ordering of the values in the $inject array must match the ordering of the parameters in MyController.

Just like with the array annotation, you’ll need to take care to keep the $inject in sync with the parameters in the function declaration.

Implicit Annotation

Careful: If you plan to minify your code, your service names will get renamed and break your app.

The simplest way to get hold of the dependencies is to assume that the function parameter names are the names of the dependencies.

someModule.controller('MyController', function($scope, greeter) {
  // ...
});

Given a function, the injector can infer the names of the services to inject by examining the function declaration and extracting the parameter names. In the above example, $scope and greeter are two services which need to be injected into the function.

One advantage of this approach is that there’s no array of names to keep in sync with the function parameters. You can also freely reorder dependencies.

However this method will not work with JavaScript minifiers/obfuscators because of how they rename parameters.

Tools like ng-annotate let you use implicit dependency annotations in your app and automatically add inline array annotations prior to minifying. If you decide to take this approach, you probably want to use ng-strict-di.

Because of these caveats, we recommend avoiding this style of annotation.

参考资料:

https://www.blacksandsolutions.co/blog/posts/debug-unknown-provider-error-with-ng-strict/

https://github.com/brandon-barker/angular-floatThead/issues/14

https://stackoverflow.com/questions/32467677/angularjs-debugging-of-injectorunpr-unknown-provider-e

https://docs.angularjs.org/guide/di#dependency-annotation

https://segmentfault.com/q/1010000005020067

MongoDB for .Net Core 查询条件之 Builders类 - hahaMan - 博客园

mikel阅读(1050)

来源: MongoDB for .Net Core 查询条件之 Builders类 – hahaMan – 博客园

使用MongoDB有段时间了 今天终于有用总结下

UpdateDefinitionBuilder,SortDefinitionBuilder,ProjectionDefinitionBuilder,IndexKeysDefinitionBuilder,FilterDefinitionBuilder应用

 

Builders

复制代码
//
// 摘要:
// A static helper class containing various builders.
//
// 类型参数:
// TDocument:
// The type of the document.
public static class Builders<TDocument>
{
//
// 摘要:
// Gets a MongoDB.Driver.FilterDefinitionBuilder`1.
public static FilterDefinitionBuilder<TDocument> Filter { get; }
//
// 摘要:
// Gets an MongoDB.Driver.IndexKeysDefinitionBuilder`1.
public static IndexKeysDefinitionBuilder<TDocument> IndexKeys { get; }
//
// 摘要:
// Gets a MongoDB.Driver.ProjectionDefinitionBuilder`1.
public static ProjectionDefinitionBuilder<TDocument> Projection { get; }
//
// 摘要:
// Gets a MongoDB.Driver.SortDefinitionBuilder`1.
public static SortDefinitionBuilder<TDocument> Sort { get; }
//
// 摘要:
// Gets an MongoDB.Driver.UpdateDefinitionBuilder`1.
public static UpdateDefinitionBuilder<TDocument> Update { get; }
}
复制代码

 

案例:

FilterDefinitionBuilder这个一般用作查询条件

复制代码
var builderlist = new List<FilterDefinition<BsonDocument>>();
builderlist.Add(Builders<BsonDocument>.Filter.Gte("EndTime", DateTime.UtcNow));
builderlist.Add(Builders<BsonDocument>.Filter.Eq("Type", BanType.Freeze));
builderlist.Add(Builders<BsonDocument>.Filter.Eq("RoleId", form.RoleId));
var filter = Builders<BsonDocument>.Filter.And(builderlist);

//同步

_mongoDbContext.Collection<BsonDocument>().Find(filter).SortByDescending(n => n.EndTime).ToList();

//异步
await _mongoDbContext.Collection<BsonDocument>().Find(filter).SortByDescending(n => n.EndTime).ToListAsync();
复制代码
UpdateDefinitionBuilder 此类用在修改数据的时候
复制代码
FilterDefinition<BsonDocument> filter = Builders<BsonDocument>.Filter.Eq("_id", id);
var list = new List<UpdateDefinition<BsonDocument>>();
list.Add(Builders<BsonDocument>.Update.Set("EndTime", DateTime.UtcNow.AddDays(day)));
list.Add(Builders<BsonDocument>.Update.Set("Operator", new UserSnapshot { Id = UserId, Name = UserName }));
list.Add(Builders<BsonDocument>.Update.Set("Remark", Remark));
list.Add(Builders<BsonDocument>.Update.Set("Category", Category));
var setfilter = Builders<BsonDocument>.Update.Combine(list);

//同步调用

_mongoDbContext.Collection<BsonDocument>().UpdateOne(filter , setfilter);

//异步调用
await _mongoDbContext.Collection<BsonDocument>().UpdateOneAsync(filter , setfilter);

复制代码

 

 

ProjectionDefinitionBuilder  查询指定的值

复制代码
//创建约束生成器
FilterDefinitionBuilder<BsonDocument> builderFilter = Builders<BsonDocument>.Filter;
ProjectionDefinitionBuilder<BsonDocument> builderProjection = Builders<BsonDocument>.Projection;
//Include 包含某元素 Exclude 不包含某元素
ProjectionDefinition<BsonDocument> projection = builderProjection.Include("RoleId");

var list = await _mongoDbContext.Collection<BsonDocument>().Find(builderFilter.Empty).Project(projection).ToListAsync();

 

//创建约束生成器
FilterDefinitionBuilder<BsonDocument> builderFilter = Builders<BsonDocument>.Filter;
ProjectionDefinitionBuilder<BsonDocument> builderProjection = Builders<BsonDocument>.Projection;
//Include 包含某元素 Exclude 不包含某元素
ProjectionDefinition<BsonDocument> projection = builderProjection.Exclude("RoleId");

_mongoDbContext.Collection<BsonDocument>().Find(builderFilter.Empty).Project(projection).ToListAsync();
复制代码

 

 

 

SortDefinitionBuilder 排序

复制代码
FilterDefinitionBuilder<BsonDocument> builderFilter = Builders<BsonDocument>.Filter;

SortDefinitionBuilder<BsonDocument> builderSort = Builders<BsonDocument>.Sort;

//排序约束 Ascending 正序 Descending 倒序
SortDefinition<BsonDocument> sort = builderSort.Ascending("RoleId");

SortDefinition<BsonDocument> sort2 = builderSort.Descending("RoleId");

var list = await _mongoDbContext.Collection<BsonDocument>().Find(builderFilter.Empty).Sort(sort).ToListAsync();
复制代码

 

Angular 1.5+ with dependency injection and uglifyjs | Maxime Rouiller

mikel阅读(734)

来源: Angular 1.5+ with dependency injection and uglifyjs | Maxime Rouiller

Here’s a problem that doesn’t come too often.

You build your own build pipeline with AngularJS and you end-up going in production with your development version. Everything runs fine.

Then you try your uglified version and… it fails. For the fix, skip to the end of the article. Otherwise? Keep on reading.

The Problem

Here’s some Stack Trace you might have in your console.

Failed to instantiate module myApp due to:

Error: [$injector:unpr] http://errors.angularjs.org/1.5.8/$injector/unpr?p0=e

and this link shows you this:

Unknown provider: e

Our Context

Now… in a sample app, it’s easy. You have few dependencies and finding them will make you go through a few files at most.

My scenario was in an application with multiple developers after many months of development. Things got a bit sloppy and we made decisions to go faster.

We already had practices in place to require developers to use explicit dependency injection instead of implicit. However, we didn’t have anything but good faith in place. Nothing against human mistake or laziness.

Implicit vs Explicit

Here’s an implicit injection

1
2
3
4
angular.module('myApp')
    .run(function($rootScope){
        //TODO: write code
    });

Here’s what it looks like explicitly (inline version)

1
2
3
4
angular.module('myApp')
    .run(['$rootScope', function($rootScope){
        //TODO: write code
    }]);

Why is it a problem?

When UglifyJS will minify your code, it will change variable names. Names that AngularJS won’t be able to match to a specific provider/injectable. That will cause the problem we have where it can’t find the right thing to inject. One thing that UglifyJS won’t touch however is strings. so the '$rootScope' present in the previous tidbit of code will stay. Angular will be able to find the proper dependency to inject. And that, even after the variable names get mangled.

The Fix

ng-strict-di will basically fails anytime it finds an implicit declaration. Make sure to put that into your main Angular template. It will save you tons of trouble.

1
2
3
<html ng-app="myApp" ng-strict-di>
...
</html>

Instead of receiving the cryptic error from before, we’ll receive something similar to this:

Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:

Error: [$injector:strictdi] function(injectables) is not using explicit annotation and cannot be invoked in strict mode

function(e) is not using explicit annotation and cannot be invoked in strict mode

mikel阅读(1186)

来源: Black Sand Solutions

Angular is awesome; but sometimes it can be difficult to decipher error messages it raises, particularly when you are just starting out.

USING NG-STRICT-DI TO Debug ANGULARJS UNKNOWN PROVIDER ERROR – OR, HOW TO FIX A MISSING $INJECTOR ERROR

A common error for the newbie and sometimes even the seasoned pro is the Unknown Provider, or $injector error. I know I fell foul of this a lot in my early days – And normally, after the site was deployed.

Here is the typical error message and associated output in the console.

Error An error has occurred. Please try again. Error: [$injector:strictdi] > http://errors.angularjs.org/1.3.16/$injector/strictdi?p0=function(n%2Ct)

injectError.pngInject Error

NG-STRICT-DI

The easiest way to Debug these errors is to catch them before the code is minified – i.e. during development. As of Angular 1.3 there is a directive called ng-strict-di which will help you find these issues.

From the documenation:

if this attribute is present on the app element, the injector will be created in “strict-di” mode. This means that the application will fail to invoke functions which do not use explicit function annotation (and are thus unsuitable for minification), as described in the Dependency Injection guide, and useful debugging info will assist in tracking down the root of these bugs.

Using this directive is simple. Add it where you declare your app.

<div ng-app=“some-angular-app” ng-strict-di=“”></div>

Then, when you forget to inject your dependencies you’ll now get an error like this:

Error: [$injector:strictdi] function($scope, > $stateParams) is not using explicit annotation and cannot be invoked in strict mode
http://errors.angularjs.org/1.3.16/$injector/strictdi?p0=function(%24scope%2C %24stateParams)

angularStrictDiMessage.pngStrict Message

CORRECTING SOME TYPICAL SCENARIOS

OK, so you forgotten to inject your dependencies, how do you resolve this?
Some common scenarios are shown below.

CONTROLLER

Probably the most common scenario, or at least the first time you are likely to see this.

angular.module(‘app’) .controller(‘AppController’, AppController); function AppController($rootScope, $scope, AppService) { }

You can prevent these errors by using the either the array notation or explicit injection. Both can be applied to controllers, services and directives alike.

My personal preference is the explicit injection which I found easier to read and follows John Papa’s StyleGuide. If you have not read this yet I strongly recommend you do.

/// array notation angular.module(‘app’) .controller(‘AppController’, [‘$rootScope’, ‘$scope’, ‘$AppService’, function AppController($rootScope, $scope, AppService){ controller code here }]);
/// explicit injection angular.module(‘app’) .controller(‘AppController’, AppController); AppController.$inject = [‘$rootScope’, ‘$scope’, ‘$AppService’]; function AppController($rootScope, $scope, AppService) { controller code here }

UIROUTER STATE CONTROLLER

The following code will generate the $inject error.

$stateProvider .state(‘someState’, { templateUrl: ‘/someTemplate’, controller: function ($scope, $stateParams) { $scope.imagePath = $stateParams.param; } })

This can be resolved either by using the array notation.

$stateProvider .state(‘someState’, { templateUrl: ‘/someTemplate’, controller: [‘$scope’, ‘$stateParams’, function($scope, $stateParams){ $scope.imagePath = $stateParams.param; } ]} })

UIROUTER STATE RESOLVE

Similarly this use of the state’s resolve property will raise the error.

$stateProvider .state(‘someState’, { templateUrl: ‘/someTemplate’, controller: someController, resolve: { someDependency: function(someService){ return someService.getData(); } }; } })

Again, use array notation to solve.

$stateProvider .state(‘someState’, { templateUrl: ‘/someTemplate’, controller: someController, { someDependency: [‘someService’, function(someService){ return someService.getData(); } ]} })

ALTERNATIVELY

An alternative approach is to not worry about this and simply let your build tools sort it out.
If you are using Grunt or Gulp it might be worth looking at ng-annotate. This task will:

add and remove AngularJS dependency injection annotations. It is non-intrusive so your source code stays exactly the same otherwise. No lost comments or moved lines. Annotations are useful because with them you’re able to minify your source code using your favorite JS minifier.
https://www.npmjs.com/package/ng-annotate

SEE ALSO

Angular DI Guide

angularjs 用uglifyJS合并压缩过程中遇见的坑_junli110的博客-CSDN博客

mikel阅读(795)

来源: angularjs 用uglifyJS合并压缩过程中遇见的坑_junli110的博客-CSDN博客

用现在很火的 nodejs 写了一个压缩 js 文件的脚本。没有用glup,webpack,而选用的uglifyJS。

不过 一开始就遇到了问题。

没有压缩合并前正常运行,可是一压缩就报错。

查找原因 ,结果是angularjs 依赖注入到Controller 中的 变量 $scope,$timeout 什么的是根据变量名匹配的,

可是压缩后 这些局部变量 的名字就变了。所以会报依赖注入错误。

  1. .controller(‘controller’, [‘$scope’, ‘$rootScope’, ‘$http’, ,
  2. function ($scope, $rootScope, $http) {
})

后来百度。在 注入的变量 前面加对应的 字符串,这样 即使 $scope 会被压缩成 E 这样的变量 ,angular 也可以按照 前面的字符串正确的注入$scope等变量。

这才是第一个 坑。后来改用了新版的 uglifyJS 后 就有 好的 使用的JS 包 ,报错了。

还以为压缩有问题,后来 百度 报的错误 才知道是因为 uglifyJS 在压缩文件的开头 加了“use strick”。

可能是 有些包不支持 所以才报错

删除压缩文件中 的 “use strick”

一切OK

AngularJs中的$scope与$rootScope_Ethan Mr.的博客-CSDN博客

mikel阅读(881)

来源: AngularJs中的$scope与$rootScope_Ethan Mr.的博客-CSDN博客

作为初次接触 AngularJS的新手,想要深层理解里面的内容短时间还是不可能的,所以标题写了浅谈字样,以下内容是参考各位大神以及相关书籍整理加个人理解,出现错误的地方请大家指正。

 

$scope(作用域),为AngularJS中MVC的核心,整理起来很麻烦, 看着大神们发的一些文章对于$scope的理解,有些方面还是看不懂,作为新手,应该站在新手的位置上去思考,所以这篇文章的目的,就是让我们这些新手初步理解$scope,懂得会用就可以了。

一、$scope概念及用法。

什么是作用域。

作用域是一个指向应用模型的对象。作用域有层次结构,有根作用域,多个子作用域,位置不同,作用不同。作用域能监控表达式和传递事件。应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带。

谈到AngularJS作用域之前,先熟悉下js中全局变量跟局部变量的差别。看下图

 

 var too="test";

        if(true){//这是在块中的定义,此时还是全局变量
            var too="new test";
        }
        alert(too=="new test");//return true;
        function test()
        {
            var too="old test";//这是在函数中的定义,此时是局部变量

        }

        test();

        alert(too=="new test");//return true;too并没有改变

这里说明,全局变量可以在方法,或者闭包内引入,而局部变量只能在定义的方法内使用,其他方法引用不到,angular作用域跟变量性质相似。想深入了解js作用域链或者全局、局部变量关系,请参考汤姆大叔博客

http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html   接下来看angular全局作用域和局部作用域区别用法:

angular中的$scope作用域可以根据需求,定义成一个变量或者是一个对象。

 

    myApp.controller('myAppCtrl', function($scope){
        //定义成变量
        $scope.book = "Angular开发指南";

        //定义成对象
        $scope.book ={
            name :'',
            author:'',
            pubTime:''
        }
    })

 

全局作用域:

var myApp = angular.module('myApp', []);

    /*
     *run方法用于初始化全局的数据,仅对全局作用域起作用。
     *这里的run方法只会在angular启动的时候运行一次。
     */
    myApp.run(function($rootScope){
        $rootScope.people ={
            name:'小明',
            age:'12',
            tel:'12233333333'
        };    
    });

全局作用域是各个 controller 中 scope 的桥梁。用 rootscope 定义的值,可以在各个 controller 中使用。经常用于的场景在多个页面切换,数据随时绑定。(若是把数据绑定在$scope局部作用域是行不通的)。

局部作用域:

myApp.controller('myAppCtrl', function($scope){
        $scope.book ={
            name :'',
            author:'',
            pubTime:''
        }
    })

    myApp.controller('myAppCtrl1',function($scope,$rootScope){
        console.log($scope.book.name);//undefined
        console.log($rootScope.people.name)  //小明                           
    })

 

二、$scope(作用域)特点

1.$scope提供了一些工具方法$watch()、$apply()

$watch()用于监听模型变化,当模型发生变化,它会提示你的。

表达式: $watch(watchExpression, listener, objectEquality);

其参数:

watchExpression:监听的对象,它可以是一个angular表达式如’name’,或函数如function(){return $scope.name}。

 listener:当watchExpression变化时会被调用的函数或者表达式,它接收3个参数:newValue(新值), oldValue(旧值), scope(作用域的引用)。

objectEquality:是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化. 如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它。

举例说明:

$scope.name = 'hello';

var watch = $scope.$watch('name',function(newValue,oldValue, scope){

        console.log(newValue);

        console.log(oldValue);

});

$timeout(function(){

        $scope.name = "world";

},1000);

$apply()用于传播模型的变化。AngularJS 外部的控制器(DOM 事件、外部的回调函数如 JQuery UI 空间等)调用了AngularJS 函数之后,必须调用$apply。

比如:

myApp.controller('myAppCtrl', function($scope){
         $scope.user = '';  
         $scope.test = function() {  
             setTimeout(function () {  
                 $scope.user = "hello";  
             }, 2000);  
         }  
      
         $scope.test1 = function() {  
              $scope.user = 'world';  
         }  
      
         $scope.test1();  
         $scope.test();  
      
         console.log($scope.user); 
    })

上例解释:

         正常理解是:在后台显示world,2秒后,会变成hello。

         实际情况是:在后台显示world,2秒后,不会成hello。

怎么才能让user自动变化呢?修改一下。

$scope.test = function() {  
    setTimeout(function () {  
        $scope.$apply(function () {  
            $scope.user = "hello";  
        });  
    }, 2000);  
}  

这样就可以了。。。。。。

2.$scope可以为一个对象传播事件,类似DOM事件。举例说明:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    <script src="dist/angular-1.3.0.14/angular.js"></script>
</head>
<body>
    <div class="form" ng-controller="myAppCtrl">
        <input type="button" value="提交" ng-click="submit()">
    </div>

    <script type="text/javascript">
        var myApp = angular.module('myApp', []);

        myApp.controller('myAppCtrl',function($scope){

            $scope.submit = function(){
                alert("提交成功!");
            }
        })
    </script>
</body>
</html>

3.$scope不仅是MVC的基础,也是实现双向数据绑定的基础。作用域提供表达式执行上下文,比如说表达式{{username}}本身是无意义的。要与作用域$scope指定的username属性中才有意义。举个栗子:

<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
    <script src="dist/angular-1.3.0.14/angular.js"></script>
</head>
<body>
    <div class="form" ng-controller="myAppCtrl">
        <input type="text" name="username" ng-model="username">{{username}}
        <input type="button" value="提交" ng-click="submit()">
    </div>

    <script type="text/javascript">
        var myApp = angular.module('myApp', []);

        myApp.controller('myAppCtrl',function($scope){

            $scope.username = '小明同学';

            $scope.submit = function(){
                alert("提交成功!");
            }
        })
    </script>
</body>
</html>

其他几点就不一一举例说明了,做些实例应该就会理解了。

4.$scope是一个POJO(Plain Old JavaScript Object)。

5.$scope是一个树型结构,与DOM标签平行。

6.子$scope对象会继承父$scope上的属性和方法。

 

三、$scope(作用域)的作用。

在特点部分中,也明显的看出来它的作用是怎样的了,下面总结一下它的作用:

  1. 提供了观察者可以监听数据模型的变化
  2. 可以将数据模型的变化通知给整个 App
  3. 可以进行嵌套,隔离业务功能和数据
  4. 给表达式提供上下文执行环境

 

四、$scope(作用域)的生命周期。

1.  创建 – 更作用域会在应用启动时通过注入器创建并注入。在模板连接阶段,一些指令会创建自己的作用域。

2.  注册观察者 – 在模板连接阶段,将会注册作用域的监听器。这也监听器被用来识别模型状态改变并更新视图。

3.  模型状态改变 – 更新模型状态必须发生在scope.$apply方法中才会被观察到。Angular框架封装了$apply过程,无需我们操心。

4.  观察模型状态 – 在$apply结束阶段,angular会从根作用域执行$digest过程并扩散到子作用域。在这个过程中被观察的表达式或方法会检查模型状态是否变更及执行更新。

5.  销毁作用域 – 当不再需要子作用域时,通过scope.$destroy()销毁作用域,回收资源。

 

接下来,$scope(作用域)与控制器、指令等之间的联系,在以后关于控制器、指令整理的文章解析,敬请期待。

(九)通过几段代码,理清angularJS中的$injector、$rootScope和$scope的概念和关联关系 - zfyouxi - 开发者的网上家园

mikel阅读(814)

来源: (九)通过几段代码,理清angularJS中的$injector、$rootScope和$scope的概念和关联关系 – zfyouxi – 开发者的网上家园

$injector、$rootScope和$scope是angularJS框架中比較重要的东西,理清它们之间的关系,对我们兴许学习和理解angularJS框架都很实用。

1、$injector事实上是一个IOC容器。包括了非常多服务(类似于spring框架中的bean),其他代码可以通过       $injector.get(“serviceName”)的方式。从injector中获取所须要的服务。

详情參考这篇文章

2、scope是angularJS中的作用域(事实上就是存储数据的地方),非常类似JavaScript的原型链。搜索的时候。优先找自己的scope,假设没有找到就沿着作用域链向上搜索。直至到达根作用域rootScope。

3、$rootScope是由angularJS载入模块的时候自己主动创建的。每一个模块仅仅会有1个rootScope。rootScope创建好会以服务的形式增加到$injector中。

也就是说通过$injector.get(“$rootScope”);可以获取到某个模块的根作用域。更准确的来说。$rootScope是由angularJS的核心模块ng创建的。

演示样例1:

// 新建一个模块
var module = angular.module("app",[]);

// true说明$rootScope确实以服务的形式包括在模块的injector中
var hasNgInjector = angular.injector(['app','ng']);  
console.log("has $rootScope=" + hasNgInjector.has("$rootScope"));//true

// 获取模块对应的injector对象,不获取ng模块中的服务
// 不依赖于ng模块,无法获取$rootScope服务
var noNgInjector = angular.injector(['app']);
console.log("no $rootScope=" + noNgInjector.has("$rootScope"));//false

// 获取angular核心的ng模块
var ngInjector = angular.injector(['ng']);  
console.log("ng $rootScope=" + ngInjector.has("$rootScope"));//true

上面的代码的确能够说明:$rootScope的确是由核心模块ng创建的,并以服务的形式存在于injector中

假设创建injector的时候,指定了ng模块,那么该injector中就会包括$rootScope服务;否则就不包括$rootScope。

演示样例2:

<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <script src="angular-1.2.25.js"></script>
	   <script>
	  
		var module = angular.module("app",[]);
		// 控制器里的$injector,是由angular框架自己主动创建的
		function FirstController($scope,$injector,$rootScope)
		{
			$rootScope.name="aty";
		}
		
		//自己创建了个injector,依赖于app和ng模块
		var myInjector = angular.injector(["app","ng"]);
		var rootScope = myInjector.get("$rootScope");
		alert(rootScope.name);//udefined
				
	   </script> 

	</head>
	
	<body ng-app="app">
		<div id="first" ng-controller="FirstController">
			<input type="text" ng-model="name">
			<br>
			{{name}}
		</div>	
	</body>
	
</html>

angular.injector()能够调用多次。每次都返回新建的injector对象。所以我们自己创建的myInjector和angular自己主动创建的$injector不是同一个对象,那么得到的rootScope也就不是同一个。更具体的能够看还有一篇文章中的

angular.injector()章节。

演示样例3:

<!doctype html>
<html lang="en">
	<head>
	   <script src="angular-1.2.25.js"></script>
	   <script>
	  
		function FirstController($scope,$injector,$rootScope)
		{
			// true
			console.log("scope parent :" + ($scope.$parent ==$rootScope));
		}
	
	   </script> 
	</head>
	
	<body ng-app>
		<div id="first" ng-controller="FirstController">
			<input type="text" ng-model="name">
			<br>
			{{name}}
		</div>	
	</body>
	
</html>

ng-controller指令给所在的DOM元素创建了一个新的$scope对象,并作为rootScope的子作用域

$scope是由$rootScope创建的,$scope不会包括在$injector中。

演示样例4:

<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <title>scope()</title>
	   <script src="jquery-1.11.1.js"></script>
	   <script src="angular-1.2.25.js"></script>
	   
	   <script>
	    
		//记住rootScope。用来推断跨控制器是否相等
		var first_rootScope = null;
		//记住scope,用来推断跨控制器是否相等
		var first_scope = null;
		//记住injector。用来推断跨控制器是否相等
		var first_injectot = null;
		
		// 第1个angular控制器
		function FirstController($scope,$injector,$rootScope)
		{
			$rootScope.name = "aty";
			first_rootScope = $rootScope;
			first_injectot = $injector;
			first_scope = $scope;	
		
		}
		
		// 第2个angular控制器,主要是来測试跨controller时injector和scope的表现
		function SecondController($scope,$injector,$rootScope)
		{
			console.log("first_rootScope==second_rootScope:" + (first_rootScope==$rootScope));//true
			console.log("first_injectot==second_injector:" + (first_injectot==$injector));//true
			console.log("first_scope==second_scope:" + (first_scope==$scope));//false
		}
	   
	   </script> 

	</head>
	
	<body ng-app>
		<div id="first" ng-controller="FirstController">
			<input type="text" ng-model="name">
			<br>
			<div id="tips"></div> 
		</div>
		
		<h2>outside of controller</h2>
		
		<br>
		<!--訪问每个应用(模块)的rootScope-->
		{{$root.name}}
		<div id="noControllerDiv"/>
		
		<div ng-controller="SecondController">
			
		</div>
		
		
	</body>
	
</html>

ng-app定义了一个angular模块,每个模块仅仅有一个$rootScope,仅仅有一个$injector,但能够有多个$scope

 

弄清了$injector、$rootScope和$scope这3者之间的关系。我们看下angular提供的2个API。一个是scope(),一个是injector()。

使用angular.element()返回的DOM对象,都会包括这2个方法,用来获取与之关联的scope和injector。

因为每一个模块的injector是唯一的。所以angular.element().injector()直接返回元素所在模块的injector

angular.element().scope()能够获取到当前元素的scope或父scope。假设当前元素有scope,则返回自己的scope;假设没有则向父亲方向寻找,假设找不到返回rootScope。即返回作用域链上。距离该元素近期的scope

<!doctype html>
<html lang="en">
	<head>
	   <meta charset="utf-8">
	   <title>scope()</title>
	   <script src="jquery-1.11.1.js"></script>
	   <script src="angular-1.2.25.js"></script>
	   
	   <script>

		function FirstController($scope,$injector,$rootScope)
		{
			//获取body对象
			var domBody = document.getElementsByTagName('body')[0];
			
			// 通过ng-app指令所在的DOM元素获取rootScope
			var rtScope = angular.element(domBody).scope();	
			
			//当前元素没有新作用域,获取父作用域即rootScope
			var noScope = angular.element("#noControllerDiv").scope();	
			
			// true
			console.log("rtScope==noScope:" + (rtScope==noScope));
			
			//ng-controller所在的元素,返回的scope
			var scopeOnController = angular.element("#first").scope();
			
			// ng-controller内部的元素返回所在的scope
			var inController = angular.element("#tips").scope();
			
			//true
			console.log("scopeOnController==inController:" + (scopeOnController==inController));
			
			//验证通过DOM获取的scope是否与注入的$scope和$rootScope一致
			//true
			console.log("result1:" + (rtScope==$rootScope));
			//true
			console.log("result2:" + (inController==$scope));

		}
	   
	   </script> 

	</head>
	
	<body ng-app>
		<div id="first" ng-controller="FirstController">
			<input type="text" ng-model="name">
			<br>
			<div id="tips"></div> 
		</div>
		
		<h2>outside of controller</h2>
		
		<br>
		<!--訪问每个应用(模块)的rootScope-->
		{{$root.name}}
		<div id="noControllerDiv"/>	
		
	</body>
	
</html>

Webpack打包 - 简书

mikel阅读(885)

来源: Webpack打包 – 简书

image.png

一. 概述

什么是webpack

模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

为什么使用webpack

现在是网络时代,在我们的生活中网络成为了必不可少的,我们在网络上可以看到很多漂亮的功能丰富的页面,这些页面都是由复杂的JavaScript代码和各种依赖包组合形成的,那么这些都是怎么*组合在一起的呢,组合在一起需要花费多少精力呢,经过漫长发展时间现前端涌现出了很多实践方法来处理复杂的工作流程,让开发变得更加简便。

  • 模块化 可以使复杂的程序细化成为各个小的文件
  • 预处理器 可以对Scss,less等CSS预先进行处理
    ……

二. weback使用流程

1、创建项目

这里用的是命令创建项目,当然你也可以去鼠标右键创建项目

mkdir webpackDemo // 创建项目
cd webpackDemo // 进入项目
mkdir app // 在项目中创建app文件
mkdir common // 在项目中创建common文件
cd app // 进入app文件夹
touch app.js // 创建app.js文件
touch main.js // 创建main.js文件
cd .. //返回到webpackDemo项目根目录
cd common // 进入common文件
touch index.html // 创建index.html文件
  • mkdir:创建文件夹
  • cd ..:返回所在目录的上级目录
  • touch:创建文件
  • app:用来存放原始数据和我们将写的JavaScript模块
  • common:用来存放之后供浏览器读取的文件(包括使用webpack打包生成的js文件以及一个index.html文件)

目录结构

image.png

基础代码
index.html是主入口,需要设置根目录并且将打包后的文件导入

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="index.js"></script>
</body>
</html>

app.js是我们写的模块,并依据CommonJS规范导出这个模块,这里我们以输出welcome to use webpack为例

module.exports = function() {
  var greet = document.createElement('div');
  greet.textContent = "welcome to use webpack!";
  return greet;
}

main.js其实是一个组件,它的目的是将我们写的一些代码模块返回并插入到页面中

const greeter = require('./app.js');
document.querySelector("#root").appendChild(greeter());
2. 安装

因为安装webpack要用npm,所以安装之前我们首先要安装node
第一步 要在项目根目录用npm init初始化,生成package.json文件

npm init

初始化过程中会有好多提示,如果非正式项目下可以直接回车调过,括号里的都是默认的,正式项目下可以根据情况填写每一步

name: (webpackDemo) // 项目名称
version: (1.0.0) // 版本号
description: // 项目的描述
entry point: (index.js) // 入口文件
test command: // 测试命令
git repository: // git仓库
keywords: // 关键字
author: // 作者创始人
 license: (ISC) //许可:(ISC)
About to write to C:\Users\Administrator\Desktop\webpackDemo\package.json:

{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this ok? (yes) // 这里直接输入yes就可以了

第二步 安装webpack

npm install webpack -g // 全局安装
npm install webpack --save-dev // 项目内安装

如果不想安装最新的版本那么得在webpack后面加一个@然后在填入你要安装的版本号,当然安装最新版本时可以加@版本号也可以不加@版本号

npm install webpack -g
npm install webpack --save-dev

webpack有两个版本分别是webpack2和webpack4,这两个版本安装配置有差异。
先来看看webpack2
本次安装的是3.5.6的版本,运行的是以下命令

npm install webpack@3.5 --save-dev

接下来看下我们创建的package.json文件,里面的都是我们刚配置的

{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.5.6"
  }
}

接下来看webpack4
webpack4版需要去额外安装webpack-cli

npm install webpack@4 --save-dev
npm install webpack@4 webpack-cli --save-dev

接下来看下配置文件

{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.5",
    "webpack-cli": "^3.2.3",
  }
}

注意:package.json文件中不能有注释,在运行的时候请将注释删除

第三步 使用Webpack打包
webpack可以在终端中使用,基本的使用方法如下:

// webpack2的命令
node_modules/.bin/webpack app/main.js common/index.js 
// webpack4的命令
node_modules/.bin/webpack app/main.js -o common/index.js
  • app/main.js:是入口文件的路径,本文中就是上述main.js的路径
  • common/index.js:是打包文件的存放路径

注意:是非全局安装情况
webpack2打包命令执行后

image.png

webpack4打包命令执行后
如果你的webpack是最新的版本webpack4那么就不能用webpack2的打包命令,如果用webpack2的命令会报错打包失败,如下:

image.png
  • 黄色部分:webpack4是需要指定打包为开发环境还是生产环境的,目前我们没有指定是什么环境所以就会有这个警告
  • 红色部分:因为webpack4的打包命令和webpack2的打包命令不同,所以用webpack2的打包命令时就会提示打包的路径找不到

如果你用webpack4的打包命令,打包如下

image.png

黄色警告下面会解决这个问题
从打包的结果可以看出webpack同时编译了main.js 和app,js,并且打包成功,现在打开编辑器,可以看到如下结果

image.png

webpack2的打包文件

image.png

webpack4的打包文件

image.png

接下来我们在看下页面

image.png

是不是很激动我们已经将welcome to use webpack!在页面打包生成,但是这种方式需要在终端运行复杂的命令而且容易出错很不方便,如果能更方便点就好了,那么接下来我们在看下它的升级版打包。

第四步 通过配置文件webpack.config.js来使用webpack
Webpack拥有很多其它的比较高级的功能,这些功能其实都可以通过命令行模式实现,但是在终端中进行复杂的操作,这样不太方便且容易出错的,更好的办法是定义一个配置文件,这个配置文件其实也是一个简单的JavaScript模块,我们可以把所有的与打包相关的信息放在里面。
在当前项目webpackDemo文件夹下新创建一个文件webpack.config.js,写入简单的配置代码,目前的配置主要涉及到的内容是入口文件路径和打包后文件的存放路径

// webpack2的配置
module.exports = {
    entry:  __dirname + "/app/main.js", // 之前提到的唯一入口文件
    output: {
        path: __dirname + "/common", // 打包后的文件存放的地方
        filename: "index.js" // 打包后输出文件的文件名
    }
}
// webpack4的配置
module.exports = {
    // webpack4需要添加这个配置,development为开发环境,production为生产环境
    mode: "development",
    entry:  __dirname + "/app/main.js", // 之前提到的唯一入口文件
    output: {
        path: __dirname + "/common", // 打包后的文件存放的地方
        filename: "index.js" // 打包后输出文件的文件名
    }
}

注:“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
有了这个配置之后,再打包文件,只需在终端里运行webpack(全局情况下)或node_modules/.bin/webpack(非全局安装需使用)命令就可以了,不需要再命令行打入主入口和打包文件的路径了,这条命令会自动引用webpack.config.js文件中的配置选项。
示例如下:

image.png
image.png

是不是很简单这样我们就不用再终端输入那么多烦人的配置文件的路径了,那么如果node_modules/.bin/webpack这条命令都不用在终端输入,是不是更简单呢?,接下来接着往下看。
更加方便的打包操作
根据上面的方式来看我们只要配置了webpack.config.js就可以将打包的路径命令省去,那么我们想是否可以以这种方式将node_modules/.bin/webpack命令省去呢? 答案是可以,只不过不是在这个文件内配置,也不用去新建文件配置。
npm可以引导任务执行,对npm进行配置后可以在命令行中使用简单的npm start命令来替代上面略微繁琐的命令。在package.json中对scripts对象进行相关设置即可,设置方法如下。

{
  "name": "webpackdemo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack" // 修改的是这里,JSON文件不支持注释,引用时请清除
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.5.6"
  }
}

注:package.json中的script会安装一定顺序寻找命令对应位置,本地的node_modules/.bin路径就在这个寻找清单中,所以无论是全局还是局部安装的Webpack,你都不需要写前面那指明详细的路径了。
npm的start命令是一个特殊的脚本名称,其特殊性表现在,在命令行中使用npm start就可以执行其对于的命令,如果对应的此脚本名称不是start,想要在命令行中运行时,需要这样用npm run {script name}npm run build,我们在命令行中输入npm start,看看输出结果是什么,输出结果如下:

image.png
image.png

现在只需要使用npm start就可以打包文件了,有没有觉得webpack也不过如此嘛,不过不要太小瞧webpack,要充分发挥其强大的功能我们还需要配置很多。

其他配置可以查看以下文章

(一)Source Maps
(二)构建本地服务器
(三)Loaders
(四)Babel
(五)模块化处理
(六)插件(Plugins)
(七)产品阶段的构建

结尾

文章到这里就要和大家告一段落了,通过这篇文章大家可以初步的了解webpack的打包流程,以及webpack的一些工具和插件,并且可以简单的去打包一些demo。
其实webpack还有很多需要我们去学习和深入了解去探索的东西。
最后祝愿大家能够早日将webpack掌握并熟练的去运用,也祝大家事业有成,最重要的一点是:“一定要注意身体吆!”

作者:秉持本心
链接:https://www.jianshu.com/p/1192cfd4a012
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

git 一个可以提高开发效率的命令:cherry-pick - 良许Linux - 博客园

mikel阅读(827)

来源: git 一个可以提高开发效率的命令:cherry-pick – 良许Linux – 博客园

各位码农朋友们一定有碰到过这样的情况:在develop分支上辛辛苦苦撸了一通代码后开发出功能模块A,B,C,这时老板过来说,年青人,我们现在先上线功能模块A,B。你一定心里一万只草泥马奔腾而过,但为了混口饭吃必须得按老板的意思办事啊。

怎么办?一个办法就是,重新建一个分支,然后再把功能模块C回退,留下功能模块A,B。这种做法不是不行,但是有更好的办法,那就是git所提供的cherry-pick功能。

cherry-pick类似于一个定制化的merge,它可以把其它分支上的commit一个个摘下来,合并到当前分支。

废话不多说,直接上实例。

比如我现在有个文件a.c,我在develop分支完成了三个功能模块:feature A,feature B,feature C。如下图:

现在,坑爹的老板只要feature A,feature B,我们现在用cherry-pick命令直接把feature A,feature B的提交合并到master分支里,如下操作:

可以看到,功能模块feature A,feature B已经被合并到master分支里。请注意,合并到master分支里的提交哈希值发生了改变,与原来的不同。

可以看出,cherry-pick命令使用方法很简单,即:

git cherry-pick commitID

刚刚是一个个提交cherry-pick到master分支,但如果有100个commit要合并到master分支呢?总不能这样一个个操作吧?git一样帮你想到了,它提供了一个区间操作方法。具体来讲是这样的:

git cherry-pick commit1..commit100

但是要注意,这是一个左开右闭的操作,也就是说,commit1不会被合并到master分支,而commit100则会。这样的话上面的需求可以如下操作来实现:

注意:上面讲到cherry-pick命令每拣选一个commit就会提交一次生成一个新的commit id。 如果我们想让每个commit 拣选后暂缓提交,等到所有commit都拣选完成后,自己手动commit,应该怎么办呢?答案是用-n 选项:

怎样,是不是很简单?学会了cherry-pick命令妈妈再也不用担心老板时不时的头脑发热了。快扫描下方二维码和良许一起学习更多git神操作!

更多精彩内容,请关注公众号良许Linux,公众内回复1024可免费获得5T技术资料,包括:Linux,C/C++,Python,树莓派,嵌入式,Java,人工智能,等等。公众号内回复进群,邀请您进高手如云技术交流群。

一篇文章搞定 Nginx 反向代理与负载均衡 - 哈喽沃德先生 - 博客园

mikel阅读(1025)

来源: 一篇文章搞定 Nginx 反向代理与负载均衡 – 哈喽沃德先生 – 博客园

要想弄明白反向代理,首先要知道啥是正向代理,要搞懂正向代理只需要知道啥是代理即可。代理其实就是一个中介,在不同事物或同一事物内部起到居间联系作用的环节。比如买票黄牛,房屋中介等等。

互联网中代理更多指的是代理服务器,代理服务器位于客户端和服务器之间,它充当两者之间的中介。这种代理在生活中是比较常见的,比如我们常说的搭个梯子上网,用到的就是代理技术。

 

2|0正向代理

 

正向代理(forward proxy):是一个位于客户端和目标服务器之间的服务器(代理服务器),为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。

比如国内访问谷歌,直接访问是不行的,我们可以通过一个能够访问谷歌的正向代理服务器,请求发到代理服务器,由代理去谷歌获取数据并返回,这样就变相的实现了访问谷歌的需求。

一句话总结:正向代理,就是代理服务器代理了客户端,去和目标服务器进行交互。

 

 

正向代理的用途

  • 突破 IP 访问限制
  • 通过缓存加速访问资源
  • 隐藏客户端真实 IP
  • 客户端访问授权

 

3|0反向代理

 

反向代理(Reverse Proxy):与正向代理正好相反,反向代理中的代理服务器,代理的是服务器那端。代理服务器接收客户端请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给客户端,此时代理服务器对外表现为一个反向代理服务器的角色。

反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。

一句话总结:反向代理,就是代理服务器代理了目标服务器,去和客户端进行交互。

 

 

反向代理的用途

  • 隐藏服务器真实 IP
  • 负载均衡
  • 通过缓存加速访问资源
  • 提供安全保障

 

4|0负载均衡

 

实际生产环境中,反向代理服务器代理的目标服务器可能不止一个。比如开发好的某个应用部署在一台 Tomcat 服务器上,而 Tomcat 的并发上限不优化情况下,默认只有两百左右,这时候为了解决高并发的问题,就只能选择更替服务器或者搭建多台服务器通过反向代理与负载均衡的技术解决并发问题。

 

 

负载均衡(Load Balance)是由多台服务器以对称的方式组成一个服务器集群,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。经过某种负载分管技术,将外部发送来的中央请求均匀分配到对称结构中的某一台服务器上。

 

5|0总结

 

正向代理,就是代理服务器代理了客户端,去和目标服务器进行交互。现实生活中的场景:黄牛买票。

反向代理,就是代理服务器代理了目标服务器,去和客户端进行交互。现实生活中的场景:房屋中介。

 

6|0Nginx 反向代理与负载均衡

 

 

前面我们提到搭建多台服务器并通过反向代理与负载均衡的技术可以解决并发问题,那么负载均衡的实现从哪来?为了避免重复造轮子,我们选择现成已有的成熟工具帮助我们完成这项工作。Nginx 就是一个不错的选择。

Nginx 是由 Igor Sysoev(伊戈尔 · 赛索耶夫)为俄罗斯访问量第二的 https://www.rambler.ru/ 站点开发的。Nginx 是一个高性能的 HTTP 和反向代理服务器,可以扛得住 5W 左右的并发。Ngnix 一方面可以做反向代理服务器,另外一方面还可以做静态资源服务器。本文主要学习如何使用 Nginx 实现反向代理与负载均衡。

官网:http://nginx.org/

 

6|1环境

 

  • 三台 CentOS 7.8.2003 机器
  • 192.168.10.101 安装 Nginx 1.18.0
  • 192.168.10.102 和 192.168.10.103 安装 Tomcat 9.0.38

 

6|2安装 Nginx

 

下载资源

 

下载 Nginx 并解压。

# 下载 nginx 压缩包 wget -P /usr/local/src http://nginx.org/download/nginx-1.18.0.tar.gz # 解压 tar -zxvf /usr/local/src/nginx-1.18.0.tar.gz -C /usr/local/src

 

安装依赖

 

Nginx 是基于 C 语言开发的,HTTP 模块使用了 pcre 来解析正则表达式,且可以使用 zlib 对 HTTP 包的内容进行 gzip 压缩,Nginx 不仅支持 HTTP 协议,还支持 HTTPS,HTTPS 需要 openssl 提供支持,所以安装 Nginx 之前必须先安装它所依赖的环境。

yum install -y gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl-devel

 

安装 Nginx

 

编译并安装。

# 切换至 nginx 的解压目录 cd /usr/local/src/nginx-1.18.0 # 创建 nginx 的安装目录 mkdir -p /usr/local/nginx # 指定 nginx 的安装路径 ./configure –prefix=/usr/local/nginx/ # 编译并安装 make && make install

 

常用命令

 

# 切换目录 cd /usr/local/nginx # 启动 sbin/nginx # 重启 sbin/nginx -s reload # 停止 sbin/nginx -s quit

 

访问

 

启动 Nginx 以后,浏览器访问:http://192.168.10.101:80/ 结果如下:

 

6|3安装 Tomcat

 

下载资源

 

下载 Tomcat 并解压。

# 下载 tomcat 压缩包 wget -P /usr/local/src https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-9/v9.0.38/bin/apache-tomcat-9.0.38.tar.gz # 创建目录 mkdir -p /usr/local/tomcat # 解压 tar -zxvf /usr/local/src/apache-tomcat-9.0.38.tar.gz -C /usr/local/tomcat

 

修改页面

 

修改 Tomcat 自带 ROOT 项目中的 index.jsp 页面。

# 编辑 index.jsp vim /usr/local/tomcat/apache-tomcat-9.0.38/webapps/ROOT/index.jsp

在 body 标签中随便添加点内容用于区分不同的服务器。

<h1 style=“color:red”>192.169.10.102:8080</h1> <h1 style=“color:red”>192.169.10.103:8080</h1>

 

启动访问

 

/usr/local/tomcat/apache-tomcat-9.0.38/bin/startup.sh 启动 Tomcat。

启动 Tomcat 以后,浏览器访问:http://192.168.10.102:8080/ 和 http://192.168.10.103:8080/ 结果如下:

 

6|4配置 Nginx

 

vim /usr/local/nginx/conf/nginx.conf 编辑配置文件。

在 http 节点下,添加 upstream 节点。使用 upstream name{} 语法定义一组服务器。

然后在 server 节点的 80 端口下添加下图中的内容。默认情况下,Nginx 是按加权轮询的方式将请求分发到各个服务器,当权重 weight 不指定时,各服务器 weight 相同。关于 Nginx 启动用户的问题请根据自身实际环境进行配置。

 

6|5反向代理负载均衡

 

通过上面的流程,我们已经完成基于 Nginx 实现反向代理 Tomcat 服务器集群与负载均衡的需求。重启 Nginx 以后,此时再访问 Nginx 则会被路由到被代理的 Tomcat 服务器上,并且采用了轮询方式(默认)的负载均衡算法。客户端请求到 Nginx 的中央请求会每台一次的平均分配至 Tomcat 每个机器上。关于 Nginx 更多详细的配置及负载均衡算法我们后面再另开文章细说。

本文采用 知识共享「署名-非商业性使用-禁止演绎 4.0 国际」许可协议

大家可以通过 分类 查看更多关于 Nginx 的文章。