我该如何向Chrome扩展发送数据?

4
我正在为我的书签扩展程序开发用户身份验证功能。该扩展程序与Google App Engine(Python)后端一起工作,网址为http://ting-1.appspot.com/
第一次运行扩展程序时,background.html会在新标签页中打开options.html,用户需要输入他的电子邮件地址。我将电子邮件地址发送到应用程序中,方法如下(尚未尝试):
in options.html
---------------

var formData = new FormData();

formData.append("extension_user", userEmail);

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://ting-1.appspot.com/authsender", true);
xhr.send(formData);

在应用程序中,处理程序AuthSender向用户发送确认电子邮件:
class AuthSender(webapp.RequestHandler):
    def post(self):
        new_user = self.request.get("extension_user") 
        mail.send_mail(
        sender="Ting <ting@gmail.com>",
        to=new_user,
        subject="Ting Bookmarking: confirm your email",
        body="""click on the link below to confirm your email: 
<a href="http://ting-1.appspot.com/authHandler"></a> 

Happy Bookmarking!""")

如果用户在电子邮件中点击链接,应用程序中的 AuthReceive 处理程序将处理请求并向扩展发送确认。但我无法弄清楚如何向扩展发送确认。 当用户点击链接时,我该如何向扩展发送确认呢?我需要再次使用 XMLHttpRequest 吗?怎么做?我需要在扩展中放置什么样的监听器? 下面是应用程序中的 AuthReceive 处理程序的简要说明:
class AuthReceive(InboundMailHandler):
    def receive(self, message):

#---------------------------------------
        #receive email // I know this part
        #send confirmation to extension // I need help with this
#--------------------------------------
...

并且在background.html文件中

//...
// add listener and save the variable to localStorage
//...

感谢您的帮助。

更新

这是符合Moishe的答案的代码。除了最后一步handler.onmessage没有触发之外,一切都正常。

options.html

<html>
<head><title>Extension Options</title></head>
<body>
<p>Enter your gmail address:</p>

<textarea id="getEmail" style="margin-bottom: 4px; width: 250px; height: 20px">
</textarea><br />

<button id="save">Save</button>
<!--<button id="save">Clear</button>-->

<script type="text/javascript">

document.getElementById("getEmail").placeholder = "your gmail address" ;

//send entered gmail address to the server
document.getElementById("save").addEventListener
(
    "click", 
    function ()
    {
        var userEmail = document.getElementById("getEmail").value;
        var formData = new FormData();
        formData.append("extension_user", userEmail);

        var channel;
        var socket;
        var handler = new Object();
        handler.onmessage =
        function (evt)
        {   
            //evt.data will be what the server sends in channel.send_message
            console.log("evt.data received from authhandler: " + evt.data);
        };    

        var xhr = new XMLHttpRequest();
        xhr.onReadyStateChange = function()
        {
            //error handling etc not included
            if (xhr.readyState == 4 && xhr.status == 200)
            {
                token = xhr.responseText;
                channel = new goog.appengine.Channel(token);
                socket = channel.open(handler);
            }
        };
        xhr.open("POST", "http://ting-1.appspot.com/authsender", true);
        xhr.send(formData);
        console.log("formData sent to authsender: " + formData);

    }, false
)
//...
</script>
</body>
</html>

AuthSender and AuthHandler

class AuthSender(webapp.RequestHandler):
    def post(self):
        new_user = self.request.get("extension_user")
        link = "http://ting-1.appspot.com/authhandler?new_user=%s" % new_user

        message = mail.EmailMessage()
        message.sender="Ting <ting@gmail.com>"
        message.to=new_user
        message.subject="Ting Bookmarking - Confirm your email"
        message.body="""Click on the link to confirm your email: %s """ % link
        message.send()

        logging.info("message sent to: %s " % message.to)

        token = channel.create_channel(new_user)
        self.response.out.write(token)

class AuthHandler(webapp.RequestHandler):
    def get(self):
        new_user = self.request.get("new_user")

        channel.send_message(new_user, new_user)

        logging.info("new_user sent to client: %s" % new_user)

工作版本

(相关问题)

options.html

<html>
<head>
    <title>Extension Options</title>
    <!-- this does not work because it is local url
    <script type="text/javascript" src="/_ah/channel/jsapi"></script>
    -->
    <script type="text/javascript" src="https://talkgadget.google.com/talkgadget/channel.js"></script>
</head>

<body>
<p>Enter your gmail address:</p>

<textarea id="getEmail" style="margin-bottom: 4px; width: 250px; height: 20px">
</textarea><br />

<button id="save">Save</button>

<script>
document.getElementById("getEmail").placeholder = "your gmail address" ;

document.getElementById("save").addEventListener
(
    "click", 
    function ()
    {
        var userEmail = document.getElementById("getEmail").value;
        var formData = new FormData();
        formData.append("extension_user", userEmail);

        var channel;
        var socket;
        var handler = 
        {
            onopen: function () { alert("onopen") },
            onerror: function () { alert("onerror") },
            onclose: function () { alert("onclose") },
            onmessage: 
            function (evt)
            {
                alert("evt.data is: " + evt.data)
            }
        };    

        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function()
        {
            if (xhr.readyState == 4 && xhr.status == 200)
            {
                token = xhr.responseText;
                channel = new goog.appengine.Channel(token);
                socket = channel.open(handler);
            }
        };
        xhr.open("POST", "http://ting-1.appspot.com/authsender", true);
        xhr.send(formData);            
    }, false
)
</script>
</body>
</html>

AuthSender and AuthHandler

class AuthSender(webapp.RequestHandler):
    def post(self):
        new_user = self.request.get("extension_user")
        link = "http://ting-1.appspot.com/authhandler?new_user=%s" % new_user

        message = mail.EmailMessage()
        message.sender="Ting <ting@gmail.com>"
        message.to=new_user
        message.subject="Ting Bookmarking - Confirm your email"
        message.body="""Click on the link to confirm your email: %s """ % link
        message.send()

        token = channel.create_channel(new_user)

        self.response.out.write(token)

class AuthHandler(webapp.RequestHandler):
    def get(self):
        new_user = self.request.get("new_user")

        self.response.out.write(new_user)

        channel.send_message(new_user, new_user)

你是不是指“电子邮件地址”而不是“电子邮件”? - kindall
@kindall; 是的,感谢您澄清。我建议在应用程序的AuthReceive处理程序中获取用户的电子邮件地址,例如userEmail = message.sender,并将此信息发送到扩展程序。我正在尝试找出如何将userEmail发送到扩展程序。再次感谢。 - Zeynel
你坚持尝试烹制自己的身份验证解决方案。Chrome-to-Phone的有什么问题吗? - Nick Johnson
@Nick Johnson,我相信Chrome-to-Phone身份验证解决方案没有问题。但是有几个原因导致我无法使用它:1.我甚至无法弄清楚要读哪个源文件。2.在我尝试阅读的文件中,我无法将与auth相关的内容与其余代码分离,以便我可以尝试使用它。3.我不明白为什么我需要使用OAuth,当我并没有尝试访问用户的任何私人数据时。4.我无法确定在我的情况下哪个是消费者,哪个是服务提供商。再次感谢您对此的帮助。 - Zeynel
@Zeynel 1. 这里 是一个很好的开始位置。2. 然后,针对如何理解代码提出具体问题!3. 因为您正在访问用户的私有数据 - 您正在存储和检索书签。这应该使用身份验证。4. 您的扩展程序是消费者。 - Nick Johnson
@Nick Johnson:感谢您的评论。那不是我正在查看的文件之一。我正在使用Python,所以需要一些时间来弄清楚这段Java代码的作用。我想知道您是否能简要概述一下,这样至少我就有一些锚点来解密代码了? - Zeynel
1个回答

5
您可以使用Channel API来完成此操作。在发出XMLHttpRequest请求的同时请求一个令牌,并打开通道以侦听消息。当您的应用程序处理与用户点击链接对应的HTTP请求时,向为该用户的扩展程序创建的通道发送消息。

更多细节:

基本上,在options.html中进行XHR请求时,可以像这样做:

var channel;
var socket;
var handler = {
  onmessage: function(evt) {
    // evt.data will be what your server sends in channel.send_message
  }
};
var xhr = new XMLHttpRequest();
xhr.onReadyStateChange = function() {
  // error handling and whatnot elided
  if (xhr.readyState == 4 and xhr.status == 200) {
    // We got a response from the server. The responseText is
    // a channel token so we can listen for a "verified" message.
    token = xhr.responseText;
    channel = new goog.appengine.Channel(token);
    socket = channel.open(handler);
  }
};
xhr.open("POST", "http://ting-1.appspot.com/authsender", true);
xhr.send(formData);

然后在您的服务器上,“authsender”页面的处理程序将执行以下操作:
class AuthSenderHandler(webapp.RequestHandler):
  def post(self):
    # get whatever data is in the form to send an email.
    # let's say that user_id is a field we extracted either from a cookie or from
    # the POST parameters themselves.
    link = "http://your.server.com/authHandler?user_id=%s" % user_id
    message = mail.EmailMessage()
    message.body = """some stuff %s""" % link
    # fill in other message fields, then send it.

    # now we'll create a channel token using the user_id and return 
    # it to the client.
    token = channel.create_channel(user_id)
    self.response.out.write(token)

以上两个函数将使您的客户端监听一个频道。接下来的步骤是:当用户点击链接时会发生什么?
以前,我们在电子邮件中发送带有user_id参数的链接(仅用于举例说明;您可能想使用其他内容)。现在,当用户点击链接时,它将向authHandler路径发出HTTP请求,并将user_id作为参数。因此,我们可以使用user_id来识别要发送消息的频道,如下所示:
class AuthHandler(webapp.RequestHandler):
  def get(self):
    user_id = self.request.get("user_id")
    # send a message indicating the user received the email and
    # verified to our client page. You may want to send other data.
    channel.send_message(user_id, "authorized")
    # probably want to show a nice "you've been authorized" page or something

然后会调用handler.onmessage回调函数,用户验证了他们的电子邮件地址后,您现在可以做任何需要做的事情。

希望这能有所帮助!


谢谢您的回答。我有一个问题。您说我应该使用HMLHttpRequest请求令牌。这怎么做呢?我还在研究文档,我的理解是应用程序(而不是客户端)需要打开通道。您能否提供更多关于顺序的线索?例如,如果客户端ID = 12345;我假设channel.create_channel(12345)将打开通道。这正确吗?再次感谢。 - Zeynel
我刚刚发布了一个关于Channel API的新问题,如果您想看一下,这是链接:http://stackoverflow.com/questions/7942814/how-can-i-use-google-app-engine-python-channel-api-with-chrome-extension 谢谢。 - Zeynel
1
上面添加了更多的细节;我认为这就避免了其他问题的需要。 - Moishe Lettvin
非常感谢您提供详细的说明。现在我可以使用/authsender将电子邮件发送给用户,当我点击电子邮件中的链接时,我发现/authhandleruser_email发送到options.html(我通过logging.info进行了检查),但options.html中的handler.onmessage没有被触发。我在options.htmlfunction (evt)中添加了日志,但它没有被记录。我做错了什么?我已经更新了我的问题,并提供了代码。(我按照建议关闭了其他问题)。再次感谢您的帮助。 - Zeynel
我认为我在读取返回的消息时遇到了JavaScript问题,所以我提出了另一个问题:http://stackoverflow.com/questions/7960751/how-to-use-onmessage-inside-addeventlistener。有什么建议吗?谢谢。 - Zeynel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接