gRPC-Web을 Kotlin 백엔드에서 시도했을 때의 메모 - 4. 웹 프론트 엔드 편
17699 단어 grpc-webnuxt.jsTypeScriptgRPC
About
이 테마의 연재, 웹 프론트 엔드 편입니다.
소개
죄송하지만 웹 프런트 엔드는 gRPC-Web을 사용하여 ReverseProxy를 통해 백엔드 gRPC 서비스와 상호 작용합니다.

이번 샘플에서는, Web 프런트 엔드는 이하의 구성으로 했습니다.
죄송하지만 웹 프런트 엔드는 gRPC-Web을 사용하여 ReverseProxy를 통해 백엔드 gRPC 서비스와 상호 작용합니다.

이번 샘플에서는, Web 프런트 엔드는 이하의 구성으로 했습니다.
Nuxt.js의 TypeScript 지원입니다.
또, 2.9부터 나름대로의 규모 변경이 들어있는 모양 자체, 아직 SSR에는 대응하고 있지 않는 것 같습니다. 이번에는 SPA 모드에서 검증했지만 SSR에서 사용하고 싶다면 다른 옵션을 고려해야 할 것 같습니다.
구성
샘플 gRPC-Web 디렉터리에 웹 프런트 엔드 프로젝트가 포함되어 있습니다.
프로젝트 만들기
웹 을 참고로 Nuxt 프로젝트를 만들었습니다.
package.json
주요 dependencies를 게시합니다.
web/package.json "dependencies": {
...
"google-protobuf": "^3.10.0-rc.1",
"grpc-web": "^1.0.6",
"vue-property-decorator": "^8.2.2"
},
"devDependencies": {
"@nuxt/typescript-build": "^0.2.6",
...
"@types/google-protobuf": "^3.7.1",
...
}
직접 추가 한 것은
"dependencies": {
...
"google-protobuf": "^3.10.0-rc.1",
"grpc-web": "^1.0.6",
"vue-property-decorator": "^8.2.2"
},
"devDependencies": {
"@nuxt/typescript-build": "^0.2.6",
...
"@types/google-protobuf": "^3.7.1",
...
}
세 가지입니다.
gRPC 클라이언트 구현
service 디렉토리를 만들고 그 아래에 gRPC 서비스 (
GreeterService
)를 호출하는 클라이언트 구현을 배치했습니다.service
├── GreeterService.ts
└── grpc ← protocで生成したファイル
├── Greeter_grpc_web_pb.d.ts
├── Greeter_grpc_web_pb.js
├── Greeter_pb.d.ts
└── Greeter_pb.js
개별적으로 살펴 보겠습니다.
protoc로 파일 생성
드디어 본제의 gRPC-Web이 등장합니다.
공식 튜토리얼 을 참고하여 protoc 플러그인으로
protoc-gen-grpc-web
를 설치합니다.protoc-gen-grpc-web 설치
$ curl -o /tmp/protoc-gen-grpc-web-1.0.6-darwin-x86_64 \
https://github.com/grpc/grpc-web/releases/download/1.0.6/protoc-gen-grpc-web-1.0.6-darwin-x86_64
$ sudo mv /tmp/protoc-gen-grpc-web-1.0.6-darwin-x86_64 \
/usr/local/bin/protoc-gen-grpc-web
$ chmod +x /usr/local/bin/protoc-gen-grpc-web
이제
protoc
명령으로 --grpc-web_out
옵션을 사용할 수 있으므로 Greeter.proto
에서 코드를 생성합니다.protoc -I=service/src/main/proto Greeter.proto \
--js_out=import_style=commonjs:web/service/grpc \
--grpc-web_out=import_style=commonjs+dts,mode=grpcwebtext:web/service/grpc
import_style
하지만 이번에는 commonjs+dts
를 지정했습니다.Experimental입니다만.
typescript
를 import하려고 할 때 컴파일 오류가 발생합니다.GreeterService.ts 구현
protoc에서 생성한 파일을 바탕으로
d.ts
에 대한 Client를 구현했습니다.web/service/GreeterService.ts
import { GreeterPromiseClient } from './grpc/Greeter_grpc_web_pb'
import { HelloRequest } from './grpc/Greeter_pb'
export default class GreeterService {
constructor(private readonly hostname: string) {
this.client = new GreeterPromiseClient(hostname, null, null)
}
private readonly client: GreeterPromiseClient
public async sayHello(name: string): Promise<{message: string; nameLength: number}> {
const request = new HelloRequest()
request.setName(name)
const response = await this.client.sayHello(request)
return Promise.resolve({
message: response.getMessage(),
nameLength: response.getNamelength()
})
}
}
Client를 Vue 인스턴스에 주입
구현한 Client를 Vue 인스턴스에 주입하기 위해 플러그인을 정의합니다.
web/plugins/greeterService.ts
import GreeterService from '~/service/GreeterService'
import { Context } from '@nuxt/types'
declare module 'vue/types/vue' {
interface Vue {
readonly $greeterService: GreeterService
}
}
export default (ctx: Context, inject: (key: string, value: any) => void) => {
const greeterService = new GreeterService(ctx.env['GRPC_HOST'])
inject('greeterService', greeterService)
}
정의한 플러그인을
GreeterService
로 로드합니다.web/nuxt.config.js
export default {
mode: 'spa',
...
/*
** Plugins to load before mounting the App
*/
plugins: [
{ src: '~plugins/greeterService.ts', ssr: false }
],
env: {
GRPC_HOST: process.env.GRPC_HOST || 'http://localhost:8080'
}
}
Component
플러그인이 Vue 인스턴스에
nuxt.config.js
를 주입하기 때문에 화면의 Component에서 호출해 보겠습니다.web/pages/index.vue
<template>
<section class="section">
<div class="container">
<h1 class="title">gRPC(gRPC-Web) Sample</h1>
<div class="field">
<label class="label">Name</label>
<div class="control">
<input v-model="name" class="input" type="text" placeholder="Name" />
</div>
</div>
<div class="control">
<button class="button is-primary" @click="send">Send</button>
</div>
<div
v-if="message && nameLength"
class="content"
style="margin-top: 0.75rem;"
>
<blockquote>{{ message }} (nameLength={{ nameLength }})</blockquote>
</div>
</div>
</section>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
@Component({ name: 'IndexPage' })
class IndexPage extends Vue {
name: string = ''
message: string | null = null
nameLength: number | null = null
async send() {
// Vueインスタンスに注入された$greeterService
const { message, nameLength } = await this.$greeterService.sayHello(
this.name
)
this.message = message
this.nameLength = nameLength
}
}
export default IndexPage
</script>
Reference
이 문제에 관하여(gRPC-Web을 Kotlin 백엔드에서 시도했을 때의 메모 - 4. 웹 프론트 엔드 편), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/hosopy/items/3800b139ce5c1b065a96텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)