javascript - 为什么来自锚元素的 http 请求不能正常工作?
问题描述
假设我有一个 HTML 页面,可以在 http://example.com/redir.php?id=someID
.
我希望一些 JavaScript 在执行时触发下载http://example.com/?file=hgc56gjyd
,并使用名称传递它newFileName
。
这是我的尝试:
var c = document.createElement("a");
c.href = "?file=hgc56gjyd";
c.download = "newFileName";
c.click();
但是当我执行这个时,实际的请求是http://example.com/redir.php?file=hgc56gjyd
. 注意添加的'redir.php'
. 此 URL 不正确,下载的文件为空。但在这种情况下,更改名称有效。
如果我写出整个 URL 或使用“/”或“./”(开头):
c.href = "http://example.com/?file=hgc56gjyd"
c.href = "/?file=hgc56gjyd"
c.href = "./?file=hgc56gjyd"
那么该download
属性不会生效,因此生成的文件不会重命名为newFileName
.
如何在获得以下功能的同时触发对正确 URI 的请求download
?
这是在 Chrome 中。
解决方案
通过做这个:
c.href = "?file=hgc56gjyd";
在 的文档中http://example.com/redir.php?id=someID
,您实际上是在执行以下操作:
c.href = "http://example.com/redir.php?file=hgc56gjyd";
// Note ---------------------^^^^^^^^^
如果你想要它http://example.com/?file=hgc56gjyd
,你不必使用绝对路径——站点内的绝对路径是坏事™ :-)——只需使用前导/
或前导./
:
c.href = "/?file=hgc56gjyd";
// -------^
或者
c.href = "./?file=hgc56gjyd";
// -------^^
/
如果您想进入域根目录而不管链接所在页面的 URL,请使用前者 ( );./
如果您只想要链接所在页面级别的默认 URL,请使用后者 ( )。在您的示例中,这些是同一件事,但如果这是在http://example.com/somethinghere/redir.php?id=someID
.
现场示例(用https://stacksnippets.net
代替http://example.com
和js
代替redir.php
):
console.log("Location: " + location);
// Your current code
var c = document.createElement("a");
c.href = "?file=hgc56gjyd";
c.download = "newFileName";
// Notice the `js` on this (which is like your redir.php)
console.log("Your Link:" + c.href);
// The corrected code (#1
var c2 = document.createElement("a");
c2.href = "/?file=hgc56gjyd";
c2.download = "newFileName";
// Notice there's no `js` now
console.log("Fix1: " + c2.href);
// The corrected code (#2
var c3 = document.createElement("a");
c3.href = "./?file=hgc56gjyd";
c3.download = "newFileName";
// Notice there's no `js` now
console.log("Fix2: " + c3.href);
.as-console-wrapper {
max-height: 100% !important;
}
在问题和评论中,您说过仅"?file=hgc56gjyd"
在重命名文件方面使用“有效”(但不下载它,您会得到一个空文件)但使用正确的路径(绝对路径或其中一个上面的解决方案)“不起作用”,因为它使用来自服务器的名称。但不同之处不在于路径本身,而在于服务器为响应路径而发送的内容:Content-Disposition
标头的文件名胜过您放入download
属性中的任何内容。实际的下载脚本 (at /
) 发送它。显然redir.php
脚本没有。
解决方案是将文件名方面转移到server,确保返回带有此标头的文档:
Content-Disposition: attachment; filename=newFileName
例如,如果下载是由 PHP 代码处理的,你会这样做:
<!-- language: lang-php -->
<?php
header("Content-Disposition: attachment; filename=newFileName")
这样,服务器就会告诉浏览器名称应该是什么。仍然允许浏览器忽略它(但以我的经验通常使用它)。
如果所有这些都失败了(例如,因为您无法更改发送该响应的服务器代码),还有一个选择:使用Blob和URL.createObjectURL
(这令人惊讶地得到很好的支持)。这是一个使用示例fetch
:
// In an event handler...
fetch("./?file=hgc56gjyd")
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.blob();
})
.then(blob => {
var c = document.createElement("a");
c.href = URL.createObjectURL(blob);
c.download = "bar.json";
c.click();
})
.catch(e => {
alert(e.message);
});
那成功地使用了这个download
名字。
如果你做不到,恐怕我认为你真的不走运。:-|
推荐阅读
- jquery - 如何在角度模板中动态插入不相同的模板?
- android - 如何实现与此类似的日历视图
- swift - 在 While 循环 Swift 中更新文本
- java - 我如何获得属于一项调查的所有问题?
- ios - 向下滚动视图时动画颜色导航栏
- javascript - JavaScript 通过 WebRTC 捕获 IP(async/await 问题)
- python - 如何在 vanilla Python 3 中监听原始以太网帧?
- c# - 检查连续数字
- javascript - 如何 get.Slice() 使用淘汰赛可观察值?
- flutter - pubspec.yaml 第 21 行第 5 列的错误:依赖项可能只有一个源