Cloud Foundry是否支持Thrift在应用程序之间进行交谈? 我找不到任何关于此的信息,似乎REST / HTTP或消息传递是应用程序间通信的首选机制。
有没有人试图在CF中使用Thrift提供服务? 是否有任何理由不支持Thrift; 或者有任何支持它的计划吗? 我更喜欢Thrift到REST进行跨语言通信,因为在Thrift中很容易生成API调用中使用的所有客户端类。 此外,它支持二进制数据传输,因此可能比REST更快。 另外我们已经有了Thrift API :)。
我猜 - 在理论上 - 客户端应用程序可以直接与另一个运行Thrift服务的CF应用程序实例对话; 但是你会失去CF目前为HTTP或消息传递提供的负载平衡优势。
Cloud Foundry Router目前仅支持HTTP / HTTPS请求的路由。 正在努力创建一个TCP路由器来处理非CF流量到CF上运行的应用程序的路由。
有一个视频预览TCP路由器将提供的一些功能,以及一个包含TCP路由器的孵化版本 ,如果您通过BOSH部署自己的CF.
cf-dev邮件列表是一个讨论其他问题的好地方。
我猜 - 在理论上 - 客户端应用程序可以直接与运行Thrift服务的另一个CF应用程序实例对话
这是正确的 - 只要配置的安全组打开了正确的端口,在CF上运行的应用程序就可以使用任何协议相互通信。
您是否可以通过HTTP和Thrift发送重要限制? 此外,我想更多地了解客户如何在您的服务上调用不同的方法。 您是否有一个通用的HTTP方法,或者您最终得到了一个类似REST的API,它反映了您的Thrift API的方法?
在处理传入请求的代码下方并返回结果。 这段代码是我前段时间为德国开发杂志撰写的文章的一部分。 整个包由一些JavaScript,一些C#和一些Delphi代码组成。 我可能会强调,我们也使用实际代码中显示的相同方法。
Delphi内置了对ISAPI的支持。 OnHandlerAction
基本上是一个事件处理程序,可以分配给选定的URL端点,或捕获所有请求。 这也意味着,我们不需要关心线程管理,因为这就是IIS为我们所做的事情。
我决定使用TJSONProtocol
有两个原因。 首先,其中一个客户端是JavaScript部分,当时只能说JSON。 第二个目标是消除任何乱码数据的风险。 在这种情况下,我从未测试过TBinaryProtocol
和TCompactProtocol
,所以我不能对这种组合说多少。
procedure TSample.OnHandlerAction( Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
const GENERIC_ERROR_JSON = '[1,"TextToolIsapi",2,0,{"2":{"rec":{"1":{"str":"Internal error: %s"}}}}]';
var b : TBytes;
s : string;
begin
try
Response.Content := TTextToolJsonServer.Process( Request.Content);
except
on e:Exception do begin
b := ( SysUtils.TEncoding.UTF8.GetBytes(e.message));
SetString( s, PAnsiChar(@b[0]), Length(b));
Response.Content := Format( GENERIC_ERROR_JSON, [s]);
end;
end;
end;
剩下的部分是(de)序列化东西并为处理器提供信息的部分。 在此示例代码中,为每个调用创建一个处理器实例。 如果这不合适,可以考虑处理器实例池等。 在我们的例子中,特定于会话的数据保存在其他地方,因此处理器实际上非常轻量级。
class function TTextToolJsonServer.Process( const aRequest : string) : string;
var handler : Samples.TTextTool.Iface;
processor : IProcessor;
protIn, protOut : IProtocol;
stmIn, stmOut : TStringStream;
begin
stmIn := nil;
stmOut := nil;
try
stmIn := TStringStream.Create( aRequest);
stmOut := TStringStream.Create;
protIn := TJSONProtocolImpl.Create(
TStreamTransportImpl.Create(
TThriftStreamAdapterDelphi.Create( stmIn, FALSE), nil));
protOut := TJSONProtocolImpl.Create(
TStreamTransportImpl.Create(
nil, TThriftStreamAdapterDelphi.Create( stmOut, FALSE)));
handler := TTextToolHandler.Create;
processor := Samples.TTextTool.TProcessorImpl.Create( handler);
processor.Process( protIn, protOut);
result := stmOut.DataString;
finally
stmIn.Free;
stmOut.Free;
end;
end;
这就是全部,其余的是标准的处理器/处理程序实现。
客户端对应方可以像这条JavaScript一样简单。 不幸的是,我手头没有Java示例,但它看起来非常相似。
function MakeClient()
{
var transport = new Thrift.Transport("bin/TextToolSample.dll");
var protocol = new Thrift.Protocol(transport);
var client = new Samples.TextToolClient(protocol);
return client;
}
function CountWords()
{
try
{
var client = MakeClient();
var nCount = client.CountWords( document.EDITOR.textinput.value);
alert("Text contains "+nCount.toString()+" words.");
}
catch (error)
{
HandleError( error)
}
}
继@ JensG建议的解决方案后,我想找到一个使用Thrift / HTTP的解决方案。 如果您的CF管理员不想支持Thrift / TCP,这是一个后备,例如,如果您的CF部署中缺少.Net buildpack意味着Thrift服务必须在CF外部托管。 我在这里分享它是因为我不明白如何让Thrift / HTTP为C#服务实现工作。 整个使用节俭0.9.3。
namespace csharp AuthServiceGenCSharp
namespace * AuthServiceGenCSharp.thrift
struct Request
{
1:string name
2:i32 age
}
struct Result
{
1:string reply
2:bool permissionGranted
}
service AuthorizationService
{
Result AskPermission(1:Request req)
}
使用Thrift编译器正常生成C#存根。 然后实现服务:
using AuthServiceGenCSharp;
namespace AuthServiceImplementation
{
/// <summary>
/// Implementation of the Thrift interface.
/// </summary>
public class AuthorizationServiceImpl : AuthorizationService.Iface
{
public Result AskPermission(Request req)
{
Result result = new Result();
result.Reply = "Hello " + req.Name;
result.PermissionGranted = true;
return result;
}
}
}
幸运的是,Thrift已经提供了一个实现IHttpHandler
接口的类: Thrift.Transport.THttpHandler 。 您所要做的就是从THttpHandler
派生您的处理程序,并传入Thrift编译器从您的IDL生成的处理器。 并指定JSON协议:
using AuthServiceGenCSharp;
using AuthServiceImplementation;
using Thrift.Protocol;
using Thrift.Transport;
// See also https://codealoc.wordpress.com/2012/04/06/thrift-over-http-with-iis/
namespace AuthServiceHTTPHandler.App_Code
{
public class AuthServiceHandler : THttpHandler
{
public AuthServiceHandler()
: base(CreateAuthProcessor(), CreateJSONFactory())
{
// We call the constructor for THttpHandler, passing in the processor we want to use (i.e., the one that
// the Thrift compiler generated from our IDL) and the protocol factory for JSON in this case.
// We can't use THttpHandler directly for 2 reasons. First, it doesn't have a no-arg constructor which
// all proper handlers must have. (At runtime you'll get this error:
// HTTP/1.1 500 Internal Server Error [MissingMethodException: Constructor on type 'Thrift.Transport.THttpHandler' not found.])
// Second, we need to tell THttpHandler which processor to use at the very least.
// Maybe Thrift should make their THttpHandler class abstract to prevent people like me from trying to use it directly!?
}
private static AuthorizationService.Processor CreateAuthProcessor()
{
return new AuthorizationService.Processor(new AuthorizationServiceImpl());
}
private static TJSONProtocol.Factory CreateJSONFactory()
{
return new TJSONProtocol.Factory();
}
}
}
(在codealoc博客上给出了一个类似的例子。)将此处理程序放在ASP.Net Web应用程序的App_Code
文件夹中。 在web.config中注册处理程序。 我在集成模式下使用IIS 7.5,所以我这样做:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<handlers>
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="AuthServiceHandler"
path="*."
verb="*"
type="AuthServiceHTTPHandler.App_Code.AuthServiceHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import AuthServiceGenCSharp.thrift.AuthorizationService.Client;
import AuthServiceGenCSharp.thrift.Request;
import AuthServiceGenCSharp.thrift.Result;
...
TTransport transport = null;
try {
transport = new THttpClient("http://localhost:9999");
} catch (TTransportException e) {
e.printStackTrace();
}
TProtocol protocol = new TJSONProtocol(transport);
Client client = new Client(protocol);
try {
transport.open();
Request request = new Request("Fred", 32);
Result result = client.AskPermission(request);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(result);
log.info("Response in JSON format: " + json);
return json;
} catch (TException e) {
e.printStackTrace();
} catch (JsonProcessingException e) {
e.printStackTrace();
} finally {
if (transport != null && transport.isOpen()) {
transport.close();
}
}
当C#ASP.NET应用程序从Visual Studio 2010发布到IIS 7.5并且Java客户端指向它时,HTTP响应正文中的Thrift响应是:
[1,"AskPermission",2,1,{"0":{"rec":{"1":{"str":"Hello Fred"},"2":{"tf":1}}}}]
和Java日志输出:
Response in JSON format: {"reply":"Hello Fred","permissionGranted":true,"setPermissionGranted":true,"setReply":true}
我最初尝试实现自定义HTTP模块 。 但是,尽管在HTTP响应中返回了正确的Thrift响应,但HTTP标头始终为405: Method Not Allowed
(Thrift客户端使用POST发送其请求)。 还有另外一篇关于此事的SO帖子 。 但是,使用HTTP处理程序可能比在长期运行中使用模块更好,因为您可以选择为长时间运行的请求创建异步处理程序 。