你能选择一个浏览器目标服务器端吗?

时间:2011-03-30 23:51:22

标签: ruby-on-rails http http-headers

我有一个表单,允许用户选择检查,并在提交时创建一个PDF,该PDF在新的浏览器选项卡中打开。它没有任何品牌,并且可能会在插件中打开,所以我不希望它接管我的网站选项卡。所以我将表单target设置为_blank

但是用户可以在没有足够信息的情况下提交表单来创建PDF,在这种情况下,我会标记错误(服务器端)并重新呈现表单。但是因为我设置了表单的目标,所以这个重新渲染也会在新标签页中打开,而不是我想要的东西 - 在这种情况下,我希望它的行为就好像target_top

所以问题是:我可以更改浏览器的渲染目标服务器端吗?

是的,我知道这可以通过客户端JavaScript来完成,但JS让我很烦,而且我还是要做验证服务器端。我可能最终不得不使用它,但请不要将它作为答案 - 如果我正在尝试甚至可以做的话,我会更好奇。

PS:我使用Ruby on Rails 2.3.8,以防有人知道特定于框架的解决方案。

2 个答案:

答案 0 :(得分:1)

解决这个问题的方法是使用pdf上的content-disposition标头,以强制下载文件,并避免整个“目标”方法..

Content-type: application/pdf

Content-Disposition: attachment; filename="downloaded.pdf"

答案 1 :(得分:0)

没有。这是一个纯粹的客户端特定功能。事实上,很有可能得到一个只支持一个窗口的浏览器,而target属性根本没有效果。甚至还有努力使这个属性完全从未来的HTML标准中消失(例如,XHTML分支没有这样的属性)。

我可以在HTML和HTTP之间考虑的唯一重叠是<meta http-equiv>标记(其中HTML可以影响HTTP控制的行为)。 HTTP是一种传输协议,旨在处理任何类型的数据。让它控制演示将是一个非常糟糕的关注点。

幸运的是,我们生活在一个支持JavaScript的世界中。使用AJAX请求验证表单相当容易,特别是对于像jQuery这样的库。

例如,此脚本对URL执行POST请求(在本例中为/pdf/validate),并期望页面发回“ok”(如果一切正常)或其他内容(如果有错误)。

<form method="post" action="/pdf/send" id="pdf-form">
    <!-- form stuff here -->
</form>

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
    // set to true if we are to bypass the check
    // this will happen once we've confirmed the parameters are okay
    var programmaticSubmit = false;

    // attach an event handler for when the form is submitted
    // this allows us to perform our own checks beforehand; we'll do so by
    // cancelling the event the user triggered, and do the submit ourselves if
    // we detect no error
    $('#pdf-form').submit(function(event)
    {
        if (!programmaticSubmit)
        {
            // first off, cancel the event
            event.preventDefault();

            // do an AJAX request to /pdf/validate
            $.ajax("/pdf/validate", {
                type: "POST",
                data: $(this).serialize(),  // send the form data as POST data
                success: function(result)
                {
                    // this gets called if the HTTP request did not end
                    // abnormally (i.e. no 4xx or 5xx status);
                    // you may also want to specify an "error" function to
                    // handle such cases
                    if (result == "ok")
                    {
                        // since the server says the data is okay, we trigger
                        // the event again by ourselves, but bypassing the
                        // checks this time
                        programmaticSubmit = true;
                        $(this).submit();
                    }
                    else // something went wrong! somehow display the error
                        alert(result);
                }
            });
        }
    });
});
</script>