Javascript 使用Angular.js-如何从需要身份验证的后端提供二进制数据?

Javascript 使用Angular.js-如何从需要身份验证的后端提供二进制数据?,javascript,angularjs,http,rest,http-headers,Javascript,Angularjs,Http,Rest,Http Headers,在我的angularjs应用程序中,我正在与需要通过http头进行基本访问身份验证的后端服务器通信。如前所述,我已经在客户端实现了身份验证机制 到目前为止,在angular应用程序中处理xhr请求的效果还不错 问题是我需要提供pdf文档的下载链接。我的后端服务器有一个/Document/Pdf/:id资源,它为应用程序/Pdf响应提供内容处置:附件,该响应也需要身份验证。我知道我不能使用xhr启动下载,但是通过ngHref提供文档下载链接,并调用函数,例如$window.open('/docum

在我的angularjs应用程序中,我正在与需要通过http头进行基本访问身份验证的后端服务器通信。如前所述,我已经在客户端实现了身份验证机制

到目前为止,在angular应用程序中处理xhr请求的效果还不错

问题是我需要提供pdf文档的下载链接。我的后端服务器有一个
/Document/Pdf/:id
资源,它为
应用程序/Pdf
响应提供
内容处置:附件
,该响应也需要身份验证。我知道我不能使用xhr启动下载,但是通过
ngHref
提供文档下载链接,并调用函数,例如
$window.open('/document/Pdf/13')
会导致服务器做出
401未经授权的
响应


我在这里遗漏了什么?

没有一个简单的解决方案。您已经发现无法通过Ajax下载,因此无法通过这种方式设置自定义头。也不能在浏览器生成的GET(如href)或POST(如表单提交)上设置自定义标题。我可以推荐三种不同的方法,所有这些方法都需要在服务器上进行一些修改:

(1) 在网页上使用Basic或Digest auth,以便浏览器生成并发送带有这些凭据的授权标头

(2) 在“授权”cookie中设置将随请求一起传递的令牌,并验证令牌服务器端

(3) 最后,我们实现这一点的方法是使用POST请求而不是GET进行下载。我们发布到同一页面上的隐藏IFrame,并让服务器在响应上设置适当的内容处置标题,如“attachment;filename=“blah.pdf”。然后,我们将授权令牌作为表单中的隐藏字段发送


所有这些都不是理想的,我知道我们的解决方案感觉有点粗糙,但我没有看到任何更优雅的方法。

在探索了@Geoff Genz提供的可能性后,添加了第四个数据uri选项,不幸的是,该选项不允许定义文件名,我决定采用另一种方法

我在API中添加了一个方法,该方法基于一个经过正常身份验证的请求生成一个一次性下载链接,并立即下载。角度处理程序变得非常简单

.factory('fileFactory', ['$http', '$window',
    function ($http, $window) {
        return {
            downloadFile: function (fileId) {
                return $http(
                    {
                        method: "POST",
                        data: fileId,
                        url: '/api/Files/RequestDownloadLink',
                        cache: false
                    }).success(function (response) {
                        var url = '/api/File/' + response.downloadId;
                        $window.location = url;
                    });
            }
        };
    }]);

这不是完美的,但我觉得是最不黑客。这对我来说也是可行的,因为我可以完全控制前端和后端。

使用解决方案(1)是否意味着每次尝试访问文档时,浏览器都会通过“需要身份验证”对话框请求用户凭据?或者是否有一些聪明的方法可以使用angular存储凭据以供浏览器使用?浏览器将在第一次请求用户凭据,然后缓存它们以供后续请求。凭据的缓存时间取决于浏览器。
.factory('fileFactory', ['$http', '$window',
    function ($http, $window) {
        return {
            downloadFile: function (fileId) {
                return $http(
                    {
                        method: "POST",
                        data: fileId,
                        url: '/api/Files/RequestDownloadLink',
                        cache: false
                    }).success(function (response) {
                        var url = '/api/File/' + response.downloadId;
                        $window.location = url;
                    });
            }
        };
    }]);