gpt4 book ai didi

node.js - HapiJS 代理问题

转载 作者:太空宇宙 更新时间:2023-11-04 00:57:43 26 4
gpt4 key购买 nike

TL;DR

如何拦截请求、对 ID 执行 ping 不同的路由、将 ID 存储在 session 中,然后使用我刚刚获得的 ID 继续原始请求(尤其是带有负载的 PUT/POST)?

背景

我正在使用 HapiJS (8) 将客户端的请求代理到现有的 API(我无法控制流程/逻辑)。 API 要求每个请求在查询字符串或有效负载中包含“ session ID”(取决于 http 方法)。为了获得 session ID,我所要做的就是索要一个...不需要用户名/密码(它在 header 中使用基本身份验证)。如果不续订, session ID 每 24 小时就会过期。每个客户端都有自己的 session ID。

我目前使用 hapi-auth-cookie 来存储 session ID 的值,当需要该 ID 时会查询该值。如果 ID 已过期或为空,我需要请求一个新 ID,然后客户端的请求才能成功代理到 API。

当前解决方案

当客户端的请求方法为“GET”时,我利用 hapi-auth-cookie docs 中描述的 appendNext 配置非常优雅地处理此挑战。该请求被 hapi-auth-cookie 拦截,如果需要新的 session ID,则会向该特定路由发送请求以获取它,API 返回该 ID,然后将其分配给 Hapi session ,然后(使用 Wreck )reply.redirect 返回到完成时的原始 GET 请求。无缝且优雅。

但是,我无法弄清楚如何使用包含数据有效负载的不同 http 方法来完成相同的流程。

除了reply.redirect之外,还有什么东西可以在保持原始有效负载和方法的同时实现相同的目标吗?还是有更好的方法来做到这一点?

代码(当前适用于“GET”请求)

主应用程序文件(hapi-auth-cookie 配置)

# register plugins
server.register require('./plugins')
, (err) ->
throw err if err

# set authentication (NLS) configs
server.auth.strategy 'session', 'cookie',
password: 'session_pwd'
cookie: 'ghsid'
redirectTo: '/api/SessionID' #get new session ID
isSecure: config.get 'ssl'
appendNext: true
ttl: config.get 'session_length'

利用 session 身份验证并调用 hapi-auth-cookie 插件的 Controller :

simpleRequest:
auth: 'session'
handler: (request, reply) ->
qs = Qs.stringify request.query
request.papi_url = "/api/route/sample?#{qs}"

reply.proxy
mapUri: (request, reply) ->
auth = config.get 'basic_auth'
api_host = config.get 'api_host'
papi_url = request.papi_url
path = api_host + papi_url
next null, path, {authorization: auth}

获取新 session ID的路由

module.exports = [

{
path: '/api/SessionID'
method: 'GET'
config: SessionController.session
}

]

session Controller

Wreck       = require 'wreck'
config = require 'config'

module.exports =
session:
description: 'Get new session ID'

auth:
mode: 'try'
strategy: 'session'

plugins:
'hapi-auth-cookie':
redirectTo: false

handler: (request, reply) ->

# request configs
papi_url = "/Session"
api_host = config.get 'api_host'
url = api_host + papi_url
opts =
headers:
'Authorization': config.get 'basic_auth'
'content-type': 'application/json;charset=UTF-8'

# make request to PAPI
Wreck.post url, opts, (err, res, body) ->
throw new Error err if err

try
bdy = JSON.parse body
sess =
nls: bdy.SessionId

if bdy.SessionId
# authenticate user with NLS
request.auth.session.set sess

# redirect to initial route
reply.redirect request.url.query.next

else
return throw new Error

catch err
throw new Error err

最终解决方案

根据马特·哈里森的回答,我创建了一个自定义插件,该插件注册为身份验证方案,以便我可以按路由控制它。

这是插件代码:

Wreck           = require 'wreck'
config = require 'config'

exports.register = (server, options, next) ->
server.auth.scheme 'cookie', internals.implementation
next()

exports.register.attributes =
name: 'Hapi Session Interceptor'
version: '1.0.0'

internals = {}

internals.implementation = (server, options, next) ->

scheme = authenticate: (request, reply) ->

validate = ->

session = request.state.sessionID
unless session
return unauthenticated()

reply.continue(credentials: {'session': session})

unauthenticated = ->

api_url = "/SessionID"
api_host = config.get 'api_host'
url = api_host + api_url
opts =
headers:
'Authorization': config.get 'basic_auth'
'content-type': 'application/json;charset=UTF-8'

# make request to API
Wreck.post url, opts, (err, res, body) ->
throw new Error err if err

bdy = JSON.parse body
sess =
session: bdy.SessionId

if bdy.SessionId
reply.state 'sessionID', bdy.SessionId
reply.continue(credentials: sess)

else
return throw new Error

validate()

return scheme

最佳答案

虽然并不完全忠实于您的代码,但我已经整理了一个示例,其中包含我认为您正在使用的所有部分。

我制作了一个service插件来代表您的 API。 upstream 插件代表您要代理的实际上游 API。

所有请求都通过服务并代理到上游,后者仅打印出收到的所有 header 和有效负载。

如果原始请求不包含带有 sessionId 的 cookie,则会在上游上点击路由以获取 cookie。当响应返回下游时,将使用该值设置 cookie。

代码在这里:https://github.com/mtharrison/hapijs-proxy-trouble

使用curl 和浏览器尝试一下。

获取: curl http://localhost:4000

POST W/PAYLOAD: curl -X POST -H "content-type: application/json"-d '{"example":"payload"}' http://本地主机:4000

index.js

var Hapi = require('hapi');

var server = new Hapi.Server();

server.connection({ port: 4000, labels: ['service'] }); // Your service
server.connection({ port: 5000, labels: ['upstream']}); // Pretend upstream API

server.state('session', {
ttl: 24 * 60 * 60 * 1000,
isSecure: false,
path: '/',
encoding: 'base64json'
});

server.register([{
register: require('./service')
}, {
register: require('./upstream')
}],
function (err) {

if (err) {
throw err;
}

server.start(function () {

console.log('Started!');
});

});

service.js

var Wreck = require('wreck');

exports.register = function (server, options, next) {

// This is where the magic happens!

server.select('service').ext('onPreHandler', function (request, reply) {

var sessionId = request.state.session;

var _done = function () {

// Set the cookie and proceed to the route

request.headers['X-Session-Id'] = sessionId;
reply.state('session', sessionId);
reply.continue();
}

if (typeof sessionId !== 'undefined')
return _done();

// We don't have a sessionId, let's get one

Wreck.get('http://localhost:5000/sessionId', {json: true}, function (err, res, payload) {

if(err) {
throw err;
}

sessionId = payload.id;

_done();
});
});

server.select('service').route({
method: '*',
path: '/{p*}', // Proxies all routes and methods
handler: {
proxy: {
host: 'localhost',
port: 5000,
protocol: 'http',
passThrough: true
}
}
});

next();
};

exports.register.attributes = {
name: 'your-service'
};

upstream.js

exports.register = function (server, options, next) {

server.select('upstream').route([{
method: '*',
path: '/{p*}',
handler: function (request, reply) {

// Just prints out what it received for headers and payload
// To prove we got send the original payload and the sessionID header

reply({
originalHeaders: request.headers,
originalPayload: request.payload,
})
}
}, {
method: 'GET',
path: '/sessionId',
handler: function (request, reply) {

// Returns a random session id

reply({ id: (Math.floor(Math.random() * 1000)) });
}
}]);

next();
};

exports.register.attributes = {
name: 'upstream'
};

关于node.js - HapiJS 代理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28949559/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com