Using Sidecar to introduce Node.js into Spring Cloud

brief introduction
Spring Cloud is a popular micro service solution at present. It combines the convenient development of Spring Boot with the rich solution of Netflix OSS. As we all know, Spring Cloud is different from Dubbo and uses Rest services based on HTTP (s) to build the whole service system.
Is it possible to develop some Rest services using some non JVM languages, such as Node.js, which we are familiar with? Yes, of course. However, if only Rest services are available, it is not possible to access the Spring Cloud system. We also want to use the Eureka provided by Spring Cloud for service discovery, use Config Server to do configuration management, and use Ribbon to do client load balancing. At this point, Spring sidecar will be able to show its talents.
Sidecar originated from Netflix Prana. He provides a HTTP API that allows access to all instances of established services, such as host, ports, etc. You can also use an embedded Zuul proxy service to get the relevant routing nodes from Eureka. Spring Cloud Config Server can be accessed directly through the host or through proxy Zuul.
What you need to be aware of is the Node.js application you have developed, and you have to implement a health check interface to allow Sidecar to report the health of this service instance to Eureka.
In order to use Sidecar, you can create a Spring Boot program with @EnableSidecar annotation. Let’s look at what this annotation has done.
@Target (ElementType.TYPE)
@Retention (RetentionPolicy.RUNTIME)
@Import (SidecarConfiguration.class)
Public @interface EnableSidecar {
Look, hystrix fuse, Eureka service discovery, zuul agent, all of these components have been opened.
Health examination
Next, we need to add the configuration of sidecar.port and in application.yml. The sidecar.port attribute represents the port of the Node.js application listener. This is to enable sidecar to register in Eureka services. is a URI that simulates the interface of Spring Boot application health indicators. It must return the following form of JSON document: health-uri-document
" status": " UP"
The application.yml of the entire Sidecar application is as follows: application.yml
Port: 5678
Name: sidecar
Port: 8000
Health-uri: http://localhost:8000/health.json
Service access
After building this application, you can use /hosts/{serviceId} API to get the result of DiscoveryClient.getInstances (). Here is an example of returning two instances of information from different /hosts/customers from host. If sidebar runs on the 5678 port, then the Node.js application can access the API through http://localhost:5678/hosts/{serviceId}.
" host": " myhost"
" port": 9000,
" uri": " http://myhost:9000"
" serviceId": " CUSTOMERS"
" secure": false
" host": " myhost2"
" port": 9000,
" uri": " http://myhost2:9000"
" serviceId": " CUSTOMERS"
" secure": false
Zuul proxy can automatically be registered to the Eureka association to /< serviceId> services add routing, so customer services can be accessed via the /customers URI. It is also assumed that sidecar listens on the 5678 port, so that our Node.js application can access the customer service through http://localhost:5678/customers.
Config Server
If we use the Config Server service and register it to Eureka, Node.js application can access it through Zull Proxy. If ConfigServer’s serviceId is configserver and Sidecar listens on the 5678 port, then you can access Config Server via http://localhost:5678/configserver. Of course, this is also due to Eureka, Config Server provides Rest interface based on HTTP protocol.
Node.js applications can also use the capabilities of Config Server to get some configuration documents, such as YAML format. For example, an access to might get the following YAML document back:
DefaultZone: http://localhost:8761/eureka/
Password: password
Description: Spring Cloud Samples
So the whole architecture of Node.js application accessing to Spring Cloud micro service cluster through Sidecar is roughly shown as follows:
Demo practice
Let’s suppose that there is such a very simple data. It is called User:
Class User {
Private Long ID;
Private String username;
Private Integer age;
It looks very classic, Kazakhstan!
Another data structure is used to represent books, Book:
Class Book {
Private Long ID;
Private Long authorId;
Private String name;
Private String publishDate;
Private String des;
Private String ISBN;
The authorId in Book corresponds to the ID of User. Now we need to develop Rest services for these two data.
First, User, we use spring to develop, first in the controller construction method, mock some false data users, and then a very simple Get interface based on the ID user.
@GetMapping (" /{id}")
Public User findById (@PathVariable Long ID) {}
After starting, we curl visited:
Curl localhost:8720/12
{" id"; 12; " username&quot:; " user12" " age&quot: 16}
Next, we use Node.js to develop Book related interfaces.
Because the Node.js community is very active, the optional Rest service framework is very large. The mainstream is express, KOA, hapi, and so on, very lightweight and easy to extend like connect. Here I consider the mass base and document richness, and choose to use express to develop such a Rest service that can be connected to Spring Cloud.
Const express = require (‘express’)
Const faker = require (‘faker/locale/zh_CN’)
Const logger = require (‘morgan’)
Const services = require (‘./service’)
Const app = Express ()
Let count = 100
Const books = new Array (count)
While (count > 0) {
Books[count] = {{
Id: count,
Name: (),
AuthorId: parseInt (Math.random () * 100) + 1,
PublishDate: ().ToLocaleString (),
Des: faker.lorem.paragraph (),
ISBN: `ISBN 000-0000-00-0`
Count —
App.use (logger (‘combined’))
/ / service health index interface
App.get (‘/health’, (req, RES) => {
Res.json ({
App.get (‘/book/: id’, (req, res, next) => {
Const id = parseInt (
If (isNaN (ID)) {
Next ()
Res.json (books[id])
/ /…
First, use faker to mock100 data, then write a simple get routing.
After startup, we visit http://localhost:3000/book/1 with browser.
Now that we have two micro services, next we launch a Sidecar instance to connect Node.js to Spring Cloud.
Public class SidecarApplication {
Public static void main (String[] args) { (SidecarApplication.class, args);
Very simple, it needs to be noted that before this, you need a eureka-server to test the ability of the sidecar agent to access Spring Config, and I also use config-server, believing that students who are familiar with spring cloud should know.
In the configuration of sidecar, bootstrap.yaml simply specifies the address of the service port and the config-server, and the node-sidecar.yaml configuration is as follows:
DefaultZone: ${EUREKA_SERVICE_URL:http://localhost:8700/eureka/}
Port: 3000
Home-page-uri: http://localhost:${sidecar.port}/
Health-uri: http://localhost:${sidecar.port}/health
Enabled: false
Here we specify the address of the node.js service directed by sidecar, and hystrix.command.default.execution.timeout.enabled: false is mainly because sidecar uses hystrix’s default timeout fuse, and the speed of domestic access to GitHub, as you know, I often timeout of config-server when I test, so I put it If you drop out of disable, you can choose to extend the overtime time.
When eureka-server, config-server, user-service, node-sidecar, node-book-service are all started, we open the http://localhost:8700/ of the main page of Eureka:
See that our services are in UP state, indicating that everything is normal. Next, look at the console of the Node.js application:
It is found that there is already traffic coming in, and the access interface is /health. Obviously, this is node-sidecar’s call to check the health of our node application.
Next is the time to witness miracles. Our curl visits the 8741 port of sidecar:
Curl localhost:8741/user-service/12
{" id"; 12; " username&quot:; " user12" " age&quot: 16}
Consistent with the results of direct access to user-service, it shows that sidecar Zuul Proxy can proxy our request to user-service services.
Well, with this agent, we hope that book services can provide the interface of author information:
Const SIDECAR = {{
Const USER_SERVICE =’user-service’
Const getUserById = (ID) => fetch (`${SIDECAR.uri}/${USER_SERVICE}/${id}`).Then ((RESP) => resp.json ())
App.get (‘/book/: bookId/author’, (req, res, next) => {
Const bookId = parseInt (req.params.bookId)
If (isNaN (bookId)) {
Next ()
Const book = books[bookId]
If (Book) {
Let uid = book.authorId
Services.getUserById (uid).Then ((user) => {
If ( {
Res.json (user)
Throw new Error (" user not found")
}).Catch ((error) => next (error))
/ / / / based on uid, filter produces all the books of authorId as UID
App.get (‘/books’, (req, res, next) => {
Const uid = req.query.uid
Res.json (books.filter ((Book) => book.authorId = = uid))
When we visit http://localhost:3000/book/2/author, we can see that we return the author information of bookId 2. But there is a problem here, and we can’t access the Node.js interface by accessing http://localhost:8741/node-sidecar/book/1 as the proxy to user-service, so how do you get user-service to get book-service data? Looking at the first part of theoretical knowledge, we can get access to various services by visiting /hosts/< serviceId>

Leave a Reply

Your email address will not be published. Required fields are marked *