ServiceStack Proxy 特性代码优化
ServiceStack Proxy Feature code optimization
我的任务是为内部系统创建代理。代理需要为每个请求添加基本身份验证 header 并记录它和响应。
我正在使用 ServiceStack 的代理功能插件,但感觉代码重复,因为我对每个操作执行以下操作:
Plugins.Add(new ProxyFeature(matchingRequests: req => req.PathInfo.ToLower().StartsWith("/opretaftale"), resolveUrl: req => gensamOpretaftaleUrl)
{
ProxyRequestFilter = (req, httpWebRequest) =>
{
try
{
httpWebRequest.AddBasicAuth(clientId, clientPassword);
}
catch (System.Exception ex)
{
Log.Error(ex, "...");
}
},
TransformRequest = async (res, requestStream) =>
{
using (var reader = new StreamReader(requestStream, Encoding.UTF8))
{
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
}
},
TransformResponse = async (res, responseStream) =>
{
using (var reader = new StreamReader(responseStream, Encoding.UTF8))
{
var responseBody = await reader.ReadToEndAsync();
Log.Information("response: " + responseBody);
return MemoryStreamFactory.GetStream(responseBody.ToUtf8Bytes());
}
}
});
是否可以对多个请求执行相同的操作?我真的需要 TransformRequest/TransformResponse 来记录 request/response 吗?我很难从 ProxyRequestFilter/ProxyResponseFilter 操作中获取流内容...
谢谢!
您可以使用普通的 C# 进行重构,例如通过将内联 lambda 提取到通用方法中并改为引用它们:
private Func<IHttpRequest, Stream, Task<Stream>> TransformRequest =>
async (res, requestStream) => {
using var reader = new StreamReader(requestStream, Encoding.UTF8);
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
};
你可以在哪里:
Plugins.Add(new ProxyFeature(...) {
TransformRequest = TransformRequest,
});
尽管在这种情况下您可能希望创建一个构造 PluginFeature 的工厂方法,例如:
ProxyFeature CreateProxyRule(Func<IHttpRequest, bool> matchingRequests,
Func<IHttpRequest, string> resolveUrl)
{
return new ProxyFeature(matchingRequests, resolveUrl)
{
ProxyRequestFilter = (req, httpWebRequest) => {
httpWebRequest.AddBasicAuth(clientId, clientPassword);
},
TransformRequest = async (res, requestStream) => {
using var reader = new StreamReader(requestStream, Encoding.UTF8);
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
},
TransformResponse = async (res, responseStream) => {
using var reader = new StreamReader(responseStream, Encoding.UTF8);
var responseBody = await reader.ReadToEndAsync();
Log.Information("response: " + responseBody);
return MemoryStreamFactory.GetStream(responseBody.ToUtf8Bytes());
}
};
}
然后只需传入所有可在不同代理之间配置的部分,例如:
Plugins.Add(CreateProxyRule(
matchingRequests: req => req.PathInfo.ToLower().StartsWith("/opretaftale"),
resolveUrl: req => gensamOpretaftaleUrl));
由于 HTTP 请求通常是仅转发流,如果您想记录正文,则需要缓冲 Request/Response,因此对于代理请求,您需要在 TransformRequest/TransformResponse 中执行此操作。
如果您只是想记录 ServiceStack 请求,您可以注册一个启用了 EnableRequestBodyTracking
的 Request Logger,例如:
Plugins.Add(new RequestLogsFeature { EnableRequestBodyTracking = true });
这将 enable Request Buffering 以便能够缓冲请求主体以进行日志记录和反序列化。
我的任务是为内部系统创建代理。代理需要为每个请求添加基本身份验证 header 并记录它和响应。
我正在使用 ServiceStack 的代理功能插件,但感觉代码重复,因为我对每个操作执行以下操作:
Plugins.Add(new ProxyFeature(matchingRequests: req => req.PathInfo.ToLower().StartsWith("/opretaftale"), resolveUrl: req => gensamOpretaftaleUrl)
{
ProxyRequestFilter = (req, httpWebRequest) =>
{
try
{
httpWebRequest.AddBasicAuth(clientId, clientPassword);
}
catch (System.Exception ex)
{
Log.Error(ex, "...");
}
},
TransformRequest = async (res, requestStream) =>
{
using (var reader = new StreamReader(requestStream, Encoding.UTF8))
{
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
}
},
TransformResponse = async (res, responseStream) =>
{
using (var reader = new StreamReader(responseStream, Encoding.UTF8))
{
var responseBody = await reader.ReadToEndAsync();
Log.Information("response: " + responseBody);
return MemoryStreamFactory.GetStream(responseBody.ToUtf8Bytes());
}
}
});
是否可以对多个请求执行相同的操作?我真的需要 TransformRequest/TransformResponse 来记录 request/response 吗?我很难从 ProxyRequestFilter/ProxyResponseFilter 操作中获取流内容...
谢谢!
您可以使用普通的 C# 进行重构,例如通过将内联 lambda 提取到通用方法中并改为引用它们:
private Func<IHttpRequest, Stream, Task<Stream>> TransformRequest =>
async (res, requestStream) => {
using var reader = new StreamReader(requestStream, Encoding.UTF8);
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
};
你可以在哪里:
Plugins.Add(new ProxyFeature(...) {
TransformRequest = TransformRequest,
});
尽管在这种情况下您可能希望创建一个构造 PluginFeature 的工厂方法,例如:
ProxyFeature CreateProxyRule(Func<IHttpRequest, bool> matchingRequests,
Func<IHttpRequest, string> resolveUrl)
{
return new ProxyFeature(matchingRequests, resolveUrl)
{
ProxyRequestFilter = (req, httpWebRequest) => {
httpWebRequest.AddBasicAuth(clientId, clientPassword);
},
TransformRequest = async (res, requestStream) => {
using var reader = new StreamReader(requestStream, Encoding.UTF8);
var requestBody = await reader.ReadToEndAsync();
Log.Information("request: " + requestBody);
return MemoryStreamFactory.GetStream(requestBody.ToUtf8Bytes());
},
TransformResponse = async (res, responseStream) => {
using var reader = new StreamReader(responseStream, Encoding.UTF8);
var responseBody = await reader.ReadToEndAsync();
Log.Information("response: " + responseBody);
return MemoryStreamFactory.GetStream(responseBody.ToUtf8Bytes());
}
};
}
然后只需传入所有可在不同代理之间配置的部分,例如:
Plugins.Add(CreateProxyRule(
matchingRequests: req => req.PathInfo.ToLower().StartsWith("/opretaftale"),
resolveUrl: req => gensamOpretaftaleUrl));
由于 HTTP 请求通常是仅转发流,如果您想记录正文,则需要缓冲 Request/Response,因此对于代理请求,您需要在 TransformRequest/TransformResponse 中执行此操作。
如果您只是想记录 ServiceStack 请求,您可以注册一个启用了 EnableRequestBodyTracking
的 Request Logger,例如:
Plugins.Add(new RequestLogsFeature { EnableRequestBodyTracking = true });
这将 enable Request Buffering 以便能够缓冲请求主体以进行日志记录和反序列化。