如何在启用HTTPS的Hapi v20服务器上解决API调用的CORS跨域问题
基础问题:你已按照教程操作启动Hapi服务器,服务运行正常但实际跨域调用不通。通过curl直接调用、浏览器直接加载API接口均可正常获得返回结果,但在Angular、React这类前端应用中调用该API端点时,会抛出如下类似错误:
Access to XMLHttpRequest at 'https://localhost:3000/server/ping' from origin 'http://localhost:5000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
实际情况确实如此:你检查响应头会发现,Access-Control-Allow-Origin 完全不在响应头列表中。因此你的应用会在预检(preflight)请求阶段就被拦截,根本不会发起实际的GET/POST请求。
以下是基于TypeScript编写的、可正常运行的Hapi v20.2.0服务器完整代码:
'use strict' import * as fs from 'fs' import * as util from 'util' import * as path from 'path' import * as os from 'os' import * as Hapi from '@hapi/hapi' import * as Http2 from 'http2' const strFullNameCert:string=path.resolve( os.homedir(), 'ssl', 'domain.crt') const strFullNameKey:string=path.resolve( os.homedir(), 'ssl', 'domain.key') const key :Buffer = fs.readFileSync(strFullNameKey) const cert:Buffer = fs.readFileSync(strFullNameCert) const sslDetails ={key,cert} const server = new Hapi.server({ listener: Http2.createSecureServer(sslDetails), // optional: remove this line for http1.1 host: 'localhost', port: 3000, tls: sslDetails, routes: { cors: true }, }) console.log(`Host : ${server.info.host}`) console.log(`Port : ${server.info.port}`) console.log(`Method : ${server.info.protocol}`) console.log(`Hapi : v${server.version}`) server.route({ method: 'GET', path:'/server/ping', handler: async (request, reply) => { console.log(`>>>ROUTE>>> : ${request.route.path}`); const response = reply.response({ qSuccess: true, qResult: 'pong' }) return response; } }) server.start()
需要重申的是,这段代码本身是可运行的,独立访问/server/ping路由可以正常获得响应。如果你是搭建提供页面服务的Web服务器,该配置基本可以满足使用需求。
但这段代码在Web应用中依旧无法通过CORS校验。 原因是什么?因为前端应用根本不会发起对/server/ping的请求,它会先发送预检OPTIONS请求,但上述代码没有对应的处理逻辑。因此无论你在server.route部分调整路由配置、添加响应头都无法解决这个问题,哪怕你在服务器实例化时尝试多种routes:cors配置也没用,因为这些配置都没有解决根本问题。
内容的提问来源于stack exchange,提问作者MotoRidingMelon

