在互联网浏览器中,文件URL“不允许加载本地资源”

29

我有一个重要的谜题。

我想在经典ASP中打开一个文件。我使用各种变量,因为事情可能会变化,但结果是正确的。我知道这一点,因为我通过复制链接地址并将其放入我的URL中进行了测试。现在的问题是:如果我点击我的链接,它什么也不做。没有刷新,没有重定向。有谁知道我做错了什么吗?

好了,问题来了。我的文件并不总是本地的,这取决于我所处的环境。如果我复制粘贴我的url的结果,它确实会下载。如果我点击我的URL,它就不会响应。有什么想法吗?浏览器问题吗?(虽然我已经测试过5个浏览器)还是其他什么原因?我真的陷在困境中,互联网似乎并不支持我。

我有3个环境。下面的变量是为了使链接起作用。我知道链接是有效的,因为我通过复制进行了测试。是的,它确实以file:///开头,而且我确定链接是正确的。

这是我的代码:

response.write("<td class='tab_kolom2'><a href='"&rootRs("pre_rootpad")&rootRs("rootpad_protocollen")&"\"&overzichtRs("Formuliernr")&"\Uitvoeringsoverzicht.xls' target='_blank' download>Click here</a></td>")

编辑:带有错误/链接结果的截图

error


1
也许只需要使用"_blank"而不是"_new window"作为目标? - user1945782
5
请查看您的输出的“源代码”,并将输出行的HTML粘贴到我们可以查看记录集中的值。此外,您似乎在使用反斜杠\代替/正斜杆/。 - Rich
@Rich 请查看我更新的帖子以获取HTML输出。反斜杠或正斜杠无所谓,两种方式都可以使用。另外,当我将链接粘贴到浏览器中时,它确实可以工作。只有链接不起作用。 - Benny Niemeijer
感谢您尝试让问题更清晰,但我们不知道rootRs("pre_rootpad")rootRs("rootpad_protocollen")内部是什么,因此显示该代码并没有帮助。我们需要看到生成的HTML输出(如@Rich所建议的那样),最好不要以C:\ 开头。 - user692942
@Lankymart,感谢你一直以来的帮助。我知道有时候我可能会很烦人。现在我下班了,但明天我会回来处理这个问题。 - Benny Niemeijer
显示剩余6条评论
6个回答

20

现在我们知道了实际错误,可以制定一个答案。

不允许加载本地资源

是Chrome和其他现代浏览器内置的安全异常。措辞可能不同,但它们都以某种方式设置了安全异常来处理此场景。

过去,您可以覆盖某些设置或应用某些标志,例如

--disable-web-security --allow-file-access-from-files --allow-file-access

在Chrome中 (请参见https://dev59.com/7nzaa4cB1Zd3GeqPWfCK#22027002)

这是有原因的

然而,值得指出的是,这些安全异常存在是有充分理由的,试图规避它们并不是最好的想法。

还有另一种方法

作为已经可以访问Classic ASP的用户,您可以构建一个中间页面来提供基于网络的文件。您可以使用ADODB.Stream对象和Response.BinaryWrite()方法的组合来实现这一点。这样做可以确保客户端永远不会暴露网络文件位置,并且由于脚本的灵活性,它可以用于从多个位置和多种文件类型加载资源。
以下是一个基本示例(“getfile.asp”):
<%
Option Explicit

Dim s, id, bin, file, filename, mime

id = Request.QueryString("id")

'id can be anything just use it as a key to identify the 
'file to return. It could be a simple Case statement like this
'or even pulled from a database.
Select Case id
Case "TESTFILE1"
  'The file, mime and filename can be built-up anyway they don't 
  'have to be hard coded.
  file = "\\server\share\Projecten\Protocollen\346\Uitvoeringsoverzicht.xls"     
  mime = "application/vnd.ms-excel"
  'Filename you want to display when downloading the resource.
  filename = "Uitvoeringsoverzicht.xls"

'Assuming other files 
Case ...
End Select

If Len(file & "") > 0 Then
  Set s = Server.CreateObject("ADODB.Stream")
  s.Type = adTypeBinary 'adTypeBinary = 1 See "Useful Links"
  Call s.Open()
  Call s.LoadFromFile(file)
  bin = s.Read()

  'Clean-up the stream and free memory
  Call s.Close()
  Set s = Nothing

  'Set content type header based on mime variable
  Response.ContentType = mime
  'Control how the content is returned using the 
  'Content-Disposition HTTP Header. Using "attachment" forces the resource
  'to prompt the client to download while "inline" allows the resource to
  'download and display in the client (useful for returning images
  'as the "src" of a <img> tag).
  Call Response.AddHeader("Content-Disposition", "attachment;filename=" & filename)
  Call Response.BinaryWrite(bin)
Else
  'Return a 404 if there's no file.
  Response.Status = "404 Not Found"
End If
%>

这个例子是伪代码,因此未经过测试。
然后可以在 <a> 中使用此脚本来返回资源;
<a href="/getfile.asp?id=TESTFILE1">Click Here</a>

这种方法可以进一步考虑,特别是对于较大的文件。可以使用Response.IsConnected检查客户端是否仍在连接,并使用s.EOS属性在读取块时检查流的结束。您还可以添加查询字符串参数以设置文件是返回内联还是提示下载。

有用的链接


这就解释了为什么它可以在旧电脑上运行。谢谢! - Benny Niemeijer
1
@BennyNiemeijer 上述方法适用于任何情况,因为它消除了暴露本地文件系统和网络路径的风险。服务器承担了大部分工作,而不是客户端。只需确保Classic ASP Web应用程序运行的帐户具有访问要读取的文件位置所需的适当权限即可。 - user692942
谢谢,它解决了问题。现在唯一的问题是它作为“_getfile.xls_”打开。我能改变名字吗? - Benny Niemeijer
1
@BennyNiemeijer 是的,Content-Disposition HTTP 头可以为您完成此操作,我会更新我的示例。 - user692942
1
谢谢,现在它已经按照预期工作了。最终这个问题可以关闭了,没有你的帮助我是做不到的,非常感谢! - Benny Niemeijer
这个答案似乎也回答了我的问题,即关于文件打开和下载的问题,但我在使用当前版本的Chrome和Edge中也遇到了使用classic ASP上传文件的问题。使用ADODB.STREAM对象对上传是否有效? - JNickVA1

11

对于不想修改Chrome安全选项的人,我们可以简单地从包含本地文件的目录中启动python http服务器:

python -m SimpleHTTPServer

并且对于 Python 3:

python3 -m http.server

现在你可以直接从你的js代码或外部访问任何本地文件,例如http://127.0.0.1:8000/some_file.txt


1
Python与经典ASP的问题有何关联? - user692942

5
您需要提供一个可以通过浏览器访问的文件链接,例如:
<a href="http://my.domain.com/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

对比

<a href="C:/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

如果您直接将“Projecten”文件夹公开给公众,则只需提供以下链接即可:
<a href="/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

但是要注意,您的文件可能会被搜索引擎索引,任何拥有此链接的人都可以访问您的文件等。请谨慎处理。

它在本地机器上,我的测试环境和生产环境(都是Intranet环境)的变量不同,并且只能由具有正确权限的人访问。测试和生产环境中的文件链接到一个文档所在的服务器(因此是根路径变量)。您只是忽略了问题的重点,即:我的链接是正确的,只是没有响应。为什么呢? - Benny Niemeijer
2
一个以"C:/..."开头的链接是无效的,正如@Rich在他的回答中所说,你可以将链接格式化为"file:///C:/...",但这只适用于你自己的机器,因为例如在我的机器上,没有C:驱动器。该链接必须指向通过IIS可访问的文件夹。类似的答案在这里:https://dev59.com/0WMl5IYBdhLWcg3woYPa#28170154 - gpinkas
你有检查其他链接是否有效吗?也就是说,这不是“浏览器”/样式/JavaScript的问题吗? - gpinkas

1

请按以下步骤操作:

  1. 使用npm install -g http-server命令,将http-server安装到angular项目中。
  2. 进入需要访问的文件位置,并打开cmd提示符,使用cmd命令http-server ./
  3. 在浏览器中使用带有端口号的任何路径进行访问(例如:120.0.0.1:8080)4.现在在您的angular应用程序中使用路径“http://120.0.0.1:8080/filename”
  4. 完美运行于我

0

我没有意识到你在原始问题中打开了本地机器上的文件,我以为你是从Web服务器向客户端发送文件。

根据您的屏幕截图,尝试将链接格式化如下:

<a href="file:///C:/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">Klik hier</a>

(由于不知道每个记录集变量的内容,我无法给出精确的ASP代码)


链接并没有错,只是它没有响应。 - Benny Niemeijer
4
@BennyNiemeijer无法获得响应是因为它不正确,这里的人真的在试图帮助你。说实话,我不知道为什么他们还要忍受你所表现出的态度。仅仅因为一个链接在浏览器之外可以工作并不意味着它在其中有效。所有本地文件链接必须以file:///开头,否则浏览器将无法理解它是本地文件资源。如果使用默认配置值运行,则某些浏览器可能还会发现访问被视为本地资源的内容受到限制。 - user692942
我甚至不知道为什么还要继续回答同样(错误)的问题。我尝试了所有的 file:/// 和非 file:/// 的方式,试了五种不同的浏览器。什么都没用。如果这是以前可以使用的东西(在我的工作旧电脑上可以使用),但现在不能使用,那就这样吧。但我知道我的链接是正确的。句号。如果我已经说了多次,我会有点失去耐心。不难理解,对吧? - Benny Niemeijer
6
实际上是的,我会告诉你为什么。你一直在谈论你尝试过什么,但在更新问题并展示你尝试过什么之前,人们将继续提出相同的建议,使你感到沮丧。你截图显示一个指向“C:....”的<a>,这已经被多次说明不起作用了,更新问题或继续让人们猜测你的意思。 - user692942

-1

您只需将HTML字符串中的所有图像网络路径替换为字节数组字符串。为此,您首先需要使用HtmlAgilityPack将Html字符串转换为Html文档。https://www.nuget.org/packages/HtmlAgilityPack

以下是用于将每个图像src网络路径(或本地路径)转换为字节数组字符串的代码。它一定会在IE、Chrome和Firefox中显示所有具有网络路径(或本地路径)的图像。

string encodedHtmlString = Emailmodel.DtEmailFields.Rows[0]["Body"].ToString();

        // Decode the encoded string.
        StringWriter myWriter = new StringWriter();
        HttpUtility.HtmlDecode(encodedHtmlString, myWriter);
        string DecodedHtmlString = myWriter.ToString();

        //find and replace each img src with byte string
         HtmlDocument document = new HtmlDocument();
         document.LoadHtml(DecodedHtmlString);
         document.DocumentNode.Descendants("img")
          .Where(e =>
        {
            string src = e.GetAttributeValue("src", null) ?? "";
            return !string.IsNullOrEmpty(src);//&& src.StartsWith("data:image");
        })
        .ToList()
                    .ForEach(x =>
                    {
                        string currentSrcValue = x.GetAttributeValue("src", null);                                
                        string filePath = Path.GetDirectoryName(currentSrcValue) + "\\";
                        string filename = Path.GetFileName(currentSrcValue);
                        string contenttype = "image/" + Path.GetExtension(filename).Replace(".", "");
                        FileStream fs = new FileStream(filePath + filename, FileMode.Open, FileAccess.Read);
                        BinaryReader br = new BinaryReader(fs);
                        Byte[] bytes = br.ReadBytes((Int32)fs.Length);
                        br.Close();
                        fs.Close();
                        x.SetAttributeValue("src", "data:" + contenttype + ";base64," + Convert.ToBase64String(bytes));                                
                    });

        string result = document.DocumentNode.OuterHtml;
        //Encode HTML string
        string myEncodedString = HttpUtility.HtmlEncode(result);

        Emailmodel.DtEmailFields.Rows[0]["Body"] = myEncodedString;

这个问题涉及到经典 ASP 而不是 ASP.Net,它们是非常不同的技术。 - user692942

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