Microservices Framework

  • You can build a cluster in service discovery and introduce multiple services with the same name
  • Introduce Nginx between the browser and the Web service as a reverse proxy

Project preparation

  1. Prepare the project environment

    1. Create project directories Web and Service
    2. Use MVC on the Web side
    3. Create common directories for the project: conf configuration file, utils utility class, bin executable, test test directory
    4. Util package import exception handling file error.go
    5. Import the front-end resource HTML/into view/
  2. Development projects

    1. Develop microservers
    2. Developing web services (clients)
  3. Database/data table preparation

    1. Create the model.go file under the project’s Web /model/.
    2. Refer to section 2.2.2 of the handout microservices Project Handout 1.MD to add the code for creating tables to Model.go
    3. Create the database search_house using SQL statements. Modify the InitDb() function. Also, specify the time when MySQL is used. Initialize the global connection pool handle.
    4. Call InitDb() in web/main.go!
    5. Run Web /main.go to create the tables you want to use in your project.

project

1. Obtain session information service

router.GET("/ API/v1.0 / session", controller.GetSession) // Register the route
Copy the code
func GetSession(ctx *gin.Context) {
	resp := make(map[string]string)
	resp["errno"] = utils.RECODE_SESSIONERR
	resp["errmsg"] = utils.RecodeText(utils.RECODE_SESSIONERR)
	ctx.JSON(http.StatusOK, resp) / / json serialization
}
Copy the code

2. Obtain the verification code image service

– Implemented on the Web

  • Go to Github and search for captcha. Filter the Go language. – afocus/captcha

  • Using the go get github.com/afocus/captcha download the source code package.

  • Follow the example code in Github to test generating image captcha

router.GET("/ API/v1.0 / imagecode / : uuid." ", controller.GetImageCd)
Copy the code
func GetImageCd(ctx *gin.Context) {
	/ / get the uuid
	uuid := ctx.Param("uuid")
	fmt.Println(uuid)
	// Generate a verification code
	cap := captcha.New() // Initialize the object
	cap.SetFont("/Users/yaxuan/go/src/bj38web/web/conf/comic.ttf") // Set the font
	cap.SetSize(128.64) // Set the verification code size
	cap.SetDisturbance(captcha.MEDIUM) // Set the interference intensity
	cap.SetFrontColor(color.RGBA{0.0.0.255}) // Set the foreground color
	cap.SetBkgColor(color.RGBA{100.0.255.255}, color.RGBA{255.0.127.255}, color.RGBA{255.255.10.255}) // Set the background color
	img,str := cap.Create(4,captcha.NUM) // Generate the font
	png.Encode(ctx.Writer, img)
	fmt.Println(str)
}
Copy the code

– Porting image captcha function to microserver – microserver

  1. Create micro service project: micro new – type the SRV bj38web/service/getCaptcha

    GetCaptcha microservice project will be added to the service/ of the project BJ38Web.

  2. Change the password this — getCaptcha/proto/getCaptcha. Proto

    syntax = "proto3";
    
    package go.micro.srv.getCaptcha;
    
    service GetCaptcha {
    	rpc Call(Request) returns (Response) {}}message Request {}message Response {
    	// Use slice to store image information with JSON serialization
    	bytes img = 1;
    }
    Copy the code
  3. Compile the proto file. — make command! Get getCaptcha.micro. Go and getCaptcha.pb.go

  4. Modify the service/getCaptcha/main. Go

import (
	"github.com/micro/go-micro/util/log"
	"github.com/micro/go-micro"
	"bj38web/service/getCaptcha/handler"

	getCaptcha "bj38web/service/getCaptcha/proto/getCaptcha"
)

func main(a) {
	// New Service
	service := micro.NewService(
		micro.Name("go.micro.srv.getCaptcha"),
		micro.Version("latest"),// Register Handler
	getCaptcha.RegisterGetCaptchaHandler(service.Server(), new(handler.GetCaptcha))

	// Run service
	iferr := service.Run(); err ! =nil {
		log.Fatal(err)
	}
}
Copy the code
  1. Modify service discovery: MDNS — > Consul
  • Initialize the consul

  • Add Consul to micro-newserive ()

    consulReg := consul.NewRegistry()
    
    // New Service
    service := micro.NewService(
        micro.Address("192.168.6.108:12341"),  // Prevent random port generation
        micro.Name("go.micro.srv.getCaptcha"),
        micro.Registry(consulReg),				// Add registration
        micro.Version("latest"),Copy the code
  • Start consul, consul agent-dev

  1. Modify the handler/getCaptcha.go file to generate verification code images
func (e *GetCaptcha) Call(ctx context.Context, req *getCaptcha.Request, rsp *getCaptcha.Response) error {
	// Generate a verification code
	cap := captcha.New() // Initialize the object
	cap.SetFont("/Users/yaxuan/go/src/bj38web/service/getCaptcha/conf/comic.ttf") // Set the font
	cap.SetSize(128.64) // Set the verification code size
	cap.SetDisturbance(captcha.MEDIUM) // Set the interference intensity
	cap.SetFrontColor(color.RGBA{0.0.0.255}) // Set the foreground color
	cap.SetBkgColor(color.RGBA{100.0.255.255}, color.RGBA{255.0.127.255}, color.RGBA{255.255.10.255}) // Set the background color
	img,_ := cap.Create(4,captcha.NUM) // Generate the font
	imgBuf, _ := json.Marshal(img) // Serialize the generated image
	rsp.Img = imgBuf // pass imgBuf out using RSP
	return nil
}
Copy the code

– Porting the image verification code function to the micro service – Web side

  1. Copy the password book. Copy proto/ under service to Web/under

  2. Import the package in GetImageCd() and alias it:

    getCaptcha "bj38web/web/proto/getCaptcha"

  3. Modify the GetImageCd function to invoke the remote service

// GetImageCd Obtain the verification code image service
func GetImageCd(ctx *gin.Context) {
	/ / get the uuid
	uuid := ctx.Param("uuid")
	fmt.Println(uuid)
	// Call the microservice function
	microClient := getCaptcha.NewGetCaptchaService("go.micro.srv.getCaptcha", client.DefaultClient)
	resp, err := microClient.Call(context.TODO(), &getCaptcha.Request{})
	iferr ! =nil {
		fmt.Println("Remote service not found")}// Deserialize the resulting data
	var img captcha.Image
	json.Unmarshal(resp.Img, &img)
	// Write the image to the browser
	png.Encode(ctx.Writer, img)
}
Copy the code

– Add redis database store on microserver (store uUID and code value of image captcha)

  • Micro server
  1. Modify the Request message body of getCaptcha. Proto in service/proto and add the UUID member. Run the make command to generate the file corresponding to getCaptcha.proto.

    message Request {
    	string uuid = 1;
    }
    Copy the code
  2. Follow the MVC code organization and create the Model directory in service/getCaptcha/

  3. Create the ModelFunc.go file wrapper and implement the SaveImgCode() function

// SaveImgCode stores the image ID to the Redis database
func SaveImgCode(code, uuid string) error {
	// 1. Connect to the database
	conn, err := redis.Dial("tcp".": 6379")
	iferr ! =nil {
		fmt.Println("redis.Dial err: ", err)
		return err
	}
	defer conn.Close()

	// 2. Operate the database -- valid for 5 minutes
	_, err = conn.Do("setex", uuid, 60*5, code)
	return err // No need to reply assistant
}
Copy the code
  1. In the Call() method of the getCapt.go file, SaveImgCode() is called after cap.create () to pass the argument.
  • Web side
  1. Modify password book! Because the microserver modified proto/, it needs to copy proto/ back to the Web

  2. Modify the Call() method parameter in web/ Controller /user.go. Initialize Request{}.

resp, err := microClient.Call(context.TODO(), &getCaptcha.Request{Uuid:uuid})
iferr ! =nil {
   fmt.Println("Remote service not found...")
   return
}
Copy the code

3. Obtain the SMS verification code

Register an Aliyun account

  1. Pass the real-name authentication
  2. Enable SMS verification code function – recharge
  3. To apply for the AccessKey

The user login name [email protected] AccessKey ID LTAI5tNXHuUUR5K9NdF29qmT AccessKey Secret v2r9Xb591gzuEGNwXsRU8IMLVFc0M2

  1. Request a signature. In this country — signature management
  2. Application template. In this country — template management
  3. The OpenAPI Explorer was used for the test

Integrate SMS captcha into the project

  1. Example Modifying a router group.

    - in the web/main.go// Add a routing group
    r1 := router.Group("/ API/v1.0")
    {
        r1.GET("/session", controller.GetSession)
        r1.GET("/imagecode/:uuid", controller.GetImageCd)
        r1.GET("/smscode/:phone", controller.GetSmscd)
    }
    Copy the code
  2. Extract the data from the Get request

    - in the web/controller/user.goGET request URL format: HTTP://IP:port/ resource path? key=value&key=value&key=value...
    
    func GetSmsCd(ctx *gin.Context) {
         // Get the phone number
         phone := ctx.Param("phone")
         // Get the request parameters
         imgCode := ctx.Query("text")
         uuid := ctx.Query("id")fmt.Println(phone, imgCode, uuid)
     }
    Copy the code
  3. Encapsulation verifies the image verification code

    -- According to MVC code architecture. Create a model/modelFunc.go
    
    // Verify the image verification code
    func CheckImgCode(uuid, imgCode string) bool {
    	/ / connect to redis
    	conn, err := redis.Dial("tcp"."192.168.6.108:6379")
    	iferr ! =nil {
    		fmt.Println("redis.Dial err:", err)
    		return false
    	}
    	defer conn.Close()
    
    	// query redis data
    	code, err := redis.String(conn.Do("get", uuid))
    	iferr ! =nil {
    		fmt.Println("Query error err:", err)
    		return false
    	}
    	
    	// Return the verification result
    	return code == imgCode
    }
    Copy the code
  4. According to the verification result, the SMS verification code is sent

    result := model.CheckImgCode(uuid, imgCode)
    if result {  // The verification succeeds
        // Send the SMS verification code
        response, _ := client.SendSms(request)
        if response.IsSuccess() {
            // Succeeded in sending the SMS verification code
        } else {
            // The sender verification code failed.}}else {
        // Verification failed
    }
    Copy the code
  5. SMS verification code is sent

    client, _ := dysmsapi.NewClientWithAccessKey("cn-hangzhou"."LTAI4FgbQXjf117SX7E75Rmn"."6icOghQlhjevrTM5PxfiB8nDTxB9z6")
    
    request := dysmsapi.CreateSendSmsRequest()
    request.Scheme = "https"
    
    request.Domain = "dysmsapi.aliyuncs.com"  // Domain name -- refer to the handout supplement!
    request.PhoneNumbers = phone
    request.SignName = Aijiren.com
    request.TemplateCode = "SMS_183242785"
    
    // Generate a random 6-digit captcha
    rand.Seed(time.Now().UnixNano())		// Seed random numbers.
    // Generate 6 random digits.
    smsCode := fmt.Sprintf("%06d", rand.Int31n(1000000))
    
    request.TemplateParam = `{"code":"` + smsCode + ` ` "}
    
    response, _ := client.SendSms(request)
    Copy the code
  6. Feedback messages are sent to the front end according to the sent results

    // Verify that the image verification code is correct
    result := model.CheckImgCode(uuid, imgCode)
    if result {
        // Send SMS messages. response, _ := client.SendSms(request)if response.IsSuccess() {
            // Succeeded in sending the SMS verification code
            resp["errno"] = utils.RECODE_OK
            resp["errmsg"] = utils.RecodeText(utils.RECODE_OK)
        } else {
            // The sender verification code failed.
            resp["errno"] = utils.RECODE_SMSERR
            resp["errmsg"] = utils.RecodeText(utils.RECODE_SMSERR)
        }
    } else {
        // The verification fails, and an error message is sent
        resp["errno"] = utils.RECODE_DATAERR
        resp["errmsg"] = utils.RecodeText(utils.RECODE_DATAERR)
    }
    Copy the code

SMS verification codes are stored in Redis

  • Use the Redis connection pool!

    // redis.Pool -- Ctrl-b check the redis library, connection Pool properties
    type Pool struct {
            Dial func(a) (Conn, error)// Connect to the database. MaxIdleint		// Max free number == Number of connections to initialize
            MaxActive int	// Maximum survival number > MaxIdle
            IdleTimeout time.Duration	// Idle timeout. MaxConnLifetime time.Duration// Maximum life cycle. }Copy the code
  • Connection pool code implementation:

    In the model/modelFunc.goTo create a Redis connection pool.// Create a global Redis connection pool handle
    var RedisPool redis.Pool
    
    // create a function to initialize the Redis connection pool
    func InitRedis(a)  {
    	RedisPool = redis.Pool{
    		MaxIdle:20,
    		MaxActive:50,
    		MaxConnLifetime:60 * 5,
    		IdleTimeout:60,
    		Dial: func(a) (redis.Conn, error) {
    			return redis.Dial("tcp"."192.168.6.108:6379")},}} -- in web/main.goInitRedis() is used to automatically initialize the connection pool when the project starts!Copy the code
  • Changed CheckImgCode() to use connection pooling.

  • Implement SaveSmsCode() to save data to Redis

    // link Redis -- get a link from the link pool
    conn := RedisPool.Get()
    defer conn.Close()
    
    // Store the SMS verification code in redis
    _, err := conn.Do("setex", phone+"_code".60 * 3, code)
    Copy the code

The SMS verification code is separated into micro services

  1. Create a microservice. “Login”, “SMS verification” and “registration” are realized using user micro-service.

    micro new --type srv bj38web/service/user

  2. Modify the password book — proto file.

    // Modify Call -- SendSms. Delete the Stream and PingPong functions.
    // Delete other message bodies except Request and Response.
    // Modify Request and Response according to incoming and outgoing
    syntax = "proto3";
    
    package go.micro.srv.user;
    
    service User {
    	rpc SendSms(Request) returns (Response) {}}message Request {
    	string phone = 1;
    	string imgCode = 2;
    	string uuid = 3;
    }
    message Response {
    	string errno = 1;
    	string errmsg = 2;
    }
    Copy the code
  3. Compile proto file to generate 2 new files xxx.micro. Go and XXX.pb. go for GRPC remote call!

    make proto
    Copy the code
  4. Transplant web/controller/user. Go “send SMS verification code” in the code, to the service/user/handler/user. Go, achieve the function of micro service version message authentication code.

  5. In the microservice project, initialize the Redis connection pool! Call InitRedis() in service/user/main.go

The SMS verification code is invoked by the client

  1. Copy the password book.
  • Copy service/user/proto/user/ to web/proto/ — the same as getCaptcha.
  1. Lead package, alias.

    • UserMicro "test_go_mod/proto/user" // Alias package
  2. Initialize the client

    microClient := userMicro.NewUserService("go.micro.srv.user"Ginseng, consulService. Client ())1: service/user/main.goThe service name specified in.Copy the code
  3. Call the remote function, wrap the call result json and send it to the browser

    resp, err := microClient.SendSms(context.TODO(), &userMicro.Request{Phone:phone, ImgCode:imgCode,Uuid:uuid})
    iferr ! =nil {
        fmt.Println("Failed to call remote function SendSms :", err)
        return
    }
    
    // Send the verification result to the browser
    ctx.JSON(http.StatusOK, resp)
    Copy the code