【问题标题】:How can I get CORS to work for API calls with a Hapi v20 server with HTTPS?如何使用带有 HTTPS 的 Hapi v20 服务器让 CORS 用于 API 调用?
【发布时间】:2021-12-10 00:26:19
【问题描述】:

基本问题:您已经按照教程进行操作,您已经启动了 Hapi 服务器,它正在运行……但它不起作用。通过 curl 直接调用会得到一些东西,使用 Web 浏览器直接加载 API 调用会得到一些东西......但是在应用程序中使用该 API 端点,比如 Angular 或 React,它会出现如下错误消息:

从源“http://localhost:5000”访问“https://localhost:3000/server/ping”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。

这是真的:您检查标题,并且 Access-Control-Allow-Origin 根本不在该列表中。因此,您的应用在预检请求中被阻止,甚至不会进行实际的 GET/POST 调用。

这是一个完整的 Hapi v20.2.0 服务器的完整文件,在 TypeScript 中:

'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 服务器来提供页面,那么这可能就足够了。

此代码在网络应用程序中仍然无法通过 CORS 验证。为什么?因为甚至永远不会发出对 /server/ping 的请求。该应用程序将首先发送预检 OPTIONS 请求。这段代码中没有任何东西可以处理它。所以 nothing 你在 server.route 区域做的,弄乱路由选项,或添加标题,将解决这个问题。在路由的主服务器实例化中有十亿个不同的设置:cors 不会解决这个问题,因为它们也没有解决实际问题。

【问题讨论】:

    标签: node.js hapijs


    【解决方案1】:

    问题是没有设置路由来处理 Chrome/Firefox 将发送的 OPTIONS 请求他们尝试 GET/POST 到 Hapi 提供的 API。将此代码添加到上述文件中,就在 server.start() 上方

    server.route({
        method : 'OPTIONS',
        path: '/{any*}',
        handler : async (request, reply) => {
            console.log(`======options: ${request.route.path}`)
            const response = reply.response({})
            response.header('Access-Control-Allow-Origin',   '*')
            response.header('Access-Control-Allow-Headers',  '*')
            return response;
            }
        })
    现在您会看到,当您尝试从您的应用程序中使用 API 时,它将进行 两次 调用:首先,选项调用,然后 如果通过了(并且现在有了这些标题)它将发出您感兴趣的实际调用。

    “cors:true”路由选项,它真的感觉就像是要“启用 cors”。我的意思是,是的……但实际上,不是。把它想象成它允许 Hapi 做 cors...你仍然需要做“处理 cors”的工作。

    【讨论】:

    • 这不是真正的正确答案。虽然您当然可以自定义 OPTIONS 处理程序,但 hapi 旨在自动响应 OPTIONS 请求,无需开发人员干预。我猜您的问题与自定义 HTTP2 侦听器有关。
    • 据我所知,这是 HTTP2 的标准内置节点侦听器。然而,使用与否并没有改变 Hapi 的反应迟钝。如果 Hapi v20 有一种工作方法来支持 SSL 和 HTTP2 并响应 OPTIONS,我很乐意看一个例子。 “它应该工作”不是stackoverflow的传统,帮帮我兄弟。 :)
    • 这是一个我为你制作的带有 hapi 的 CORS 的实例。我没有尝试使用 HTTP2,因为您说您的设置即使使用 HTTP1.1 也无法正常工作。希望这会有所帮助。如果不是,我怀疑您使用的是不受浏览器信任的自签名 SSL 证书,因此请确保浏览器信任它,并且您可以在直接访问 API 时看到 API 响应(没有 CORS 发挥作用)。 codesandbox.io/s/purple-bash-ydmlj?file=/src/index.js
    • 感谢您的努力!但是,您误读了我的帖子:我发布的上述初始服务器可以使用 http1.1 或 http2。我用 LetsEncrypt certbot cert 让你的代码在完全解析的机器上运行:对不起,它不能解决问题。它与许多现有示例(以及我的工作顶级版本)相似,如果直接询问,它将提供数据。您的 API 服务器,就像我没有 OPTIONS 路由的顶级版本一样,在从 Angular 之类的应用程序中调用时失败,Chrome 将强制执行 CORS 并显示相同的错误消息:没有为 OPTIONS 请求发送“Access-Control-Allow-Origin”标头。
    • 所以如果我将 React 添加到我的示例中,你会认为它是有效的证明吗?
    【解决方案2】:

    我在中间件顶部添加了这些,以响应选项(飞行前)请求。 可能会导致使用这些选项的应用程序的其他区域出现问题,但适用于我的案例/问题。

    async function(request: Request, h: ResponseToolkit) {
      if (request.method === "options") {
        const response = h.response({});
        response.header("Access-Control-Allow-Origin", "*");
        response.header("Access-Control-Allow-Headers", "*");
        return h.response(response).takeover();
      }
    
      // more checks....
    },
    

    【讨论】:

      猜你喜欢
      • 2018-02-09
      • 1970-01-01
      • 2018-12-19
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      • 1970-01-01
      • 2019-08-21
      • 2018-10-19
      相关资源
      最近更新 更多