ゆずめも

メモ的なブログです。主に勉強した事について書いてます。

Nest.jsで特定のAPIだけset-cookieを削除する

gaeにデプロイされているNest.jsプロジェクトで、レスポンスをエッジサーバーにキャッシュさせたい。

tl;dr

  • いい感じのHeader設定すればキャッシュできそう
  • csurf使ってるとset-cookieが邪魔
  • interceptorでresponseのheaderからset-cookieヘッダーを削除

GAEでキャッシュを効かせるための方法

以下の記事を見るにCache-Controlヘッダーを設定してやればいいっぽい

cloud.google.com

qiita.com

nestjsでの実現方法

Cache-Controlを設定するだけであれば@Headerデコレータを使えばできそう

docs.nestjs.com

csurfを使ってるとできなかった

csrfの対策でcsurfというmiddlewareを使用していて、これがset-cookieを返していて上記のgcpの記事を見ているとキャッシュできないっぽかった。

csurfのソースコードを見てもset-cookieを回避する方法がなかったので、なんとかキャッシュできないかとNest.jsのドキュメントを眺めているとinterceptorで特定のエンドポイントだけset-cookieを削除する方法を思いついた。

docs.nestjs.com

やってみた

csurfの導入はしている前提でNest.jsのプロジェクトを作成したらデフォルトでできるcontrollerで実験してみる。

interceptorを定義

// interceptor.ts
import {CallHandler, ExecutionContext, NestInterceptor} from '@nestjs/common'
import {Observable} from 'rxjs'

export class RemoveSetCookieInterceptor implements NestInterceptor {
  intercept(
    context: ExecutionContext,
    next: CallHandler<any>
  ): Observable<any> | Promise<Observable<any>> {
    const res = context.switchToHttp().getResponse()
    res.removeHeader('set-cookie')
    return next.handle()
  }
}

Nest.jsのinterceptorのドキュメントを参考にcontrollerに@UseInterceptorのデコレーターを設定

# before
$ curl -I 'http://localhost:3000/'
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Vary: Origin
Access-Control-Allow-Credentials: true
set-cookie: _csrf=3vAswtvct-xiqGdjiPYXpz6v; Max-Age=3600000; Path=/; HttpOnly
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"
Date: Mon, 14 Dec 2020 09:33:57 GMT
Connection: keep-alive
Keep-Alive: timeout=5

# after
curl -I 'http://localhost:3000/'
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"
Date: Mon, 14 Dec 2020 09:37:13 GMT
Connection: keep-alive
Keep-Alive: timeout=5

これで特定のheaderを削除できるようになったので乱用はできないけどキャッシュはできそう。