我有一个外部 Web 应用程序,它有后端 (nodeJs) 和客户端 (Vue)。 现在我们想在反向代理后面使用这个 Web 应用程序(不是 Nginx,因为我们实现了一个内部逻辑来绕过一些逻辑)。
我们发现应用程序正在使用 sse 来更新 UI,因此现在我们还应该支持 sse 代理请求。我们使用 NestJs 来代理所有有效的 http 请求,现在我们陷入了 sse 请求。
这就是我们实现
sse
控制器的方式
@Sse('/rest/push')
async proxyPushMessages(@Res({ passthrough: true }) response: FastifyReply, @Req() request: any) {
const sseStream = this.sseProxyService.proxySSE(request);
response.header('Content-Type', 'text/event-stream');
response.header('Cache-Control', 'no-cache');
response.header('Connection', 'keep-alive');
sseStream.subscribe(
(messageEvent) => {
return response.send(`data: ${messageEvent.data}`);
},
(error) => {
console.error('SSE Error:', error);
return response.send(`data: ${error}`);
},
() => {
return response.send(`data: ${'SSE stream closed'}`);
},
);
}
这是 sse 代理服务,它将请求代理到应用程序后端
import { map, Observable } from 'rxjs';
import { HttpService } from '@nestjs/axios';
import { FastifyRequest, Injectable } from '@transmit-security/bindid-services-core-service';
import { AxiosRequestConfig } from 'axios';
const baseWorkflowsUrl = process.env.WORKFLOWS_SERVER_URL || 'http://localhost:5678';
@Injectable()
export class SSEProxyService {
constructor(private httpService: HttpService) {}
private buildUrl(url: string): string {
return `${baseWorkflowsUrl}${url}`;
}
proxySSE(req: FastifyRequest): Observable<MessageEvent> {
const { url, method, headers } = req;
const reqObject: AxiosRequestConfig = {
url: this.buildUrl(url),
withCredentials: true,
responseType: 'text',
method,
headers: headers as any,
};
return this.httpService.request(reqObject).pipe(map((response) => new MessageEvent('message', response.data)));
}
}
看起来推送请求已解决,但用户界面仍然没有更新。 我缺少什么?
最终我通过使用
http-proxy-middleware
npm lib 在幕后处理它来解决它。
代码示例
this.proxy = createProxyMiddleware({
target: process.env.WORKFLOWS_SERVER_URL,
secure: false,
ws: true,
onProxyRes: (proxyRes: any, req: any, res: any) => {
res.setHeader(
'Content-Security-Policy',
`default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self' ${process.env.WORKFLOWS_SERVER_URL} 'unsafe-inline' 'unsafe-eval' ;script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests`,
);
},
});
}