无法打开本地文件 - Chrome:不允许加载本地资源。

186

浏览器测试: Chrome版本:52.0.2743.116

这是一个简单的JavaScript,旨在从本地打开像'C:\002.jpg'这样的图像文件。

function run(){

   var URL = "file:///C:\002.jpg";

   window.open(URL, null);

}
run();

这是我的示例代码。 https://fiddle.jshell.net/q326vLya/3/

请给我任何适当的建议。


1
使用<input type=file>来访问本地资源。 - dandavis
我成功地绕过了这个痛苦的“特性”,方法是将图像移动到我的wwwroot目录(与Css和js存储在同一目录中),并将其引用为“./Img.jpg”。我正在使用Visual Studio和C#。 - Alan
16个回答

114

2
Woody:非常感谢!这种方法对我很有帮助。我在Windows 10上运行本地Tomcat + 本地AWS S3存储桶。现在我可以在实时的AWS服务器和本地服务器之间切换了。干杯。Q - user1723453
2
谢谢Woody,但你知道有更好的方法吗?每次都需要启动它。我想要一些后台被动扩展,只需启用访问file:///。 - Mohammad_Hosein
1
很抱歉,@Mohammad_Hosein。我不知道是否有更简单的Chrome插件。许多学生使用EasyPHP Dev https://www.easyphp.org/。对于技术倾向的人,还有lite-server https://github.com/johnpapa/lite-server | https://www.freecodecamp.org/news/how-you-can-use-lite-server-for-a-simple-development-web-server-33ea527013c9/。 - Woody
3
除非你允许访问你的本地计算机,否则没有任何伤害。你正在使用本地端口来使用你的计算机。如果你将本地端口暴露给外部世界,那么你就会犯下一个巨大的错误。 - Woody
2
对我来说,它没有起作用。 - Ionut
显示剩余2条评论

56

1) 打开终端并输入

npm install -g http-server

2) 进入您要提供文件的根目录,然后输入:

http-server ./

3) 阅读终端输出,类似 http://localhost:8080 的东西将会出现。

其中所有内容都允许被获取。例如:

background: url('http://localhost:8080/waw.png');


http-server现在存在问题,导致出现错误 - 你可以将其降级到0.9版本来解决 - 参见https://dev59.com/xVMI5IYBdhLWcg3wZKZQ - Brian Burns
1
这对我来说是最简单的答案。百分之百有效。谢谢! - robrecord
这台 Windows 机器非常被锁定。 "npm" 肯定没有被安装,也永远不会被安装。任何未经企业网络安全批准的软件都不能被安装。 - mnemotronic
在非管理员PowerShell控制台会话中,我发现跳过第1步并在确认已安装nodejs后直接运行“npx http-server”对于第2步非常有用。 - Chris Smith
非常容易做到,而且完美运作!感谢分享。 - justdoingmyjob

33

好的,大家好,我完全理解这个错误信息背后的安全原因,但有时候我们确实需要一个变通方法...这就是我的方法。它使用ASP.Net(而不是这个问题基于的JavaScript),但希望对某些人有用。

我们公司内部的应用程序有一个网页,用户可以在其中创建一个快捷方式列表,以便访问网络中分散的有用文件。当他们点击其中一个快捷方式时,我们希望能够打开这些文件...但当然,Chrome的错误会阻止这一点。

enter image description here

这个网页使用AngularJS 1.x列出各种快捷方式。
最初,我的网页试图直接创建一个指向文件的<a href..>元素,但是当用户点击其中一个链接时,这会产生“不允许加载本地资源”的错误。
<div ng-repeat='sc in listOfShortcuts' id="{{sc.ShtCut_ID}}" class="cssOneShortcutRecord" >
    <div class="cssShortcutIcon">
        <img ng-src="{{ GetIconName(sc.ShtCut_PathFilename); }}">
    </div>
    <div class="cssShortcutName">
        <a ng-href="{{ sc.ShtCut_PathFilename }}" ng-attr-title="{{sc.ShtCut_Tooltip}}" target="_blank" >{{ sc.ShtCut_Name }}</a>
    </div>
</div>

解决方法是用以下代码替换那些<a href..>元素,调用我 Angular 控制器中的一个函数...
<div ng-click="OpenAnExternalFile(sc.ShtCut_PathFilename);" >
    {{ sc.ShtCut_Name }}
</div>

这个函数本身非常简单...

$scope.OpenAnExternalFile = function (filename) {
    //
    //  Open an external file (i.e. a file which ISN'T in our IIS folder)
    //  To do this, we get an ASP.Net Handler to manually load the file, 
    //  then return it's contents in a Response.
    //
    var URL = '/Handlers/DownloadExternalFile.ashx?filename=' + encodeURIComponent(filename);
    window.open(URL);
}

在我的ASP.Net项目中,我添加了一个名为DownloadExternalFile.aspx的处理程序文件,其中包含以下代码:
namespace MikesProject.Handlers
{
    /// <summary>
    /// Summary description for DownloadExternalFile
    /// </summary>
    public class DownloadExternalFile : IHttpHandler
    {
        //  We can't directly open a network file using Javascript, eg
        //      window.open("\\SomeNetworkPath\ExcelFile\MikesExcelFile.xls");
        //
        //  Instead, we need to get Javascript to call this groovy helper class which loads such a file, then sends it to the stream.  
        //      window.open("/Handlers/DownloadExternalFile.ashx?filename=//SomeNetworkPath/ExcelFile/MikesExcelFile.xls");
        //
        public void ProcessRequest(HttpContext context)
        {
            string pathAndFilename = context.Request["filename"];               //  eg  "\\SomeNetworkPath\ExcelFile\MikesExcelFile.xls"
            string filename = System.IO.Path.GetFileName(pathAndFilename);      //  eg  "MikesExcelFile.xls"

            context.Response.ClearContent();

            WebClient webClient = new WebClient();
            using (Stream stream = webClient.OpenRead(pathAndFilename))
            {
                // Process image...
                byte[] data1 = new byte[stream.Length];
                stream.Read(data1, 0, data1.Length);

                context.Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", filename));
                context.Response.BinaryWrite(data1);

                context.Response.Flush();
                context.Response.SuppressContent = true;
                context.ApplicationInstance.CompleteRequest();
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

就是这样。

现在,当用户点击我的快捷方式链接之一时,它调用OpenAnExternalFile函数,该函数打开此.ashx文件,并将要打开的文件的路径+文件名传递给它。

此处理程序代码加载文件,然后在HTTP响应中返回其内容。

工作完成,网页打开外部文件。

呼!再说一遍 - Chrome抛出“Not allowed to load local resources”异常有原因,所以请小心...但我发布这个代码只是为了证明这是一个相当简单的方法来解决这个限制。

最后一条评论:原始问题想要打开文件“C:\002.jpg”。你不能这样做。您的网站将位于一个服务器上(带有自己的C:驱动器),并且无法直接访问用户自己的C:驱动器。因此,您最好使用像我的代码这样的代码来访问网络驱动器上的文件。


1
听起来不错,但是你如何处理授权(读取权限)?如果并非所有用户都被允许查看给定的文件怎么办?难道你不需要以请求用户的名义执行读取操作吗? - Timi
你为什么要使用WebClient打开本地文件?而对于我来说,它试图打开C:\ SomeNetworkPath \ ... - Kev
如果我们不使用Angular,是否仍然可能实现? - Ahmad.Tr
这是一个有用的答案,但如果您有数百张图片通过这个ashx句柄被渲染和下载,它将非常影响网页的加载时间。 - Jamshaid K.
我喜欢这个答案,但我觉得我需要给它点个踩,因为这肯定会被一些安全意识较低的开发人员复制粘贴,他们将无意中添加一种方式,使任何人都可以访问服务器具有访问权限的任何文件。 - Marie
1
@Marie - 感谢您的反馈。真诚地说,之前没有人有礼貌地解释他们为什么要对我进行投票,所以我很感激。我确实同意,这确实提供了绕过Chrome安全机制的后门,但在我的公司内部应用程序中,这种解决方案是必需的,并且是一个救命稻草。但是,正如我所说...要小心! - Mike Gledhill

18

5
我尝试按照解决方案“c:\path\chrome.exe” -allow-file-access-from-files 进行操作,但无法打开它。请测试此网站https://fiddle.jshell.net/q326vLya/3/。我做错了什么? - KBH
13
在GoogleChrome 66中它无法运行。Chrome已经使用了相应的标志,但仍显示无法打开本地文件。 - Radon8472
6
请修改答案。它已经不起作用了。 - Mohammad_Hosein

13

有一个解决办法,可以使用Web Server for Chrome
以下是步骤:

  1. 在 Chrome 中添加扩展程序。
  2. 选择文件夹(C:\images)并在所需端口上启动服务器。

现在可以轻松访问您本地的文件:

function run(){
   // 8887 is the port number you have launched your serve
   var URL = "http://127.0.0.1:8887/002.jpg";

   window.open(URL, null);

}
run();

提示:如果您遇到任何跨域访问错误,可能需要从高级设置中选择CORS标头选项。


谢谢。但你知道有更好的方法吗?它需要每次启动。我想要一些后台被动扩展,只需启用访问 file:///。 - Mohammad_Hosein

7

当我使用PHP作为服务器端语言时,出现了这个问题,解决方法是在将结果发送给客户端之前生成图像的base64编码。

$path = 'E:/pat/rwanda.png';
$type = pathinfo($path, PATHINFO_EXTENSION);
$data = file_get_contents($path);
$base64 = 'data:image/' . $type . ';base64,' . base64_encode($data);

我认为这可能会给某人创造自己的工作的想法。
谢谢。

4

由于安全原因,Google Chrome不允许加载本地资源。Chrome需要http URL。Internet Explorer和Edge允许加载本地资源,但是Safari、Chrome和Firefox不允许加载本地资源。

转到文件位置并从那里启动Python服务器。

python -m SimpleHttpServer

然后将该URL放入函数中:

function run(){
var URL = "http://172.271.1.20:8000/" /* http://0.0.0.0:8000/ or http://127.0.0.1:8000/; */
window.open(URL, null);
}

2
或者,使用Python 3,python -m http.server - andybega

2
如果您安装了php,您可以使用内置服务器。只需打开包含文件的目标目录并运行即可。
php -S localhost:8001

2
如果您能够这样做,那将代表一个巨大的安全问题,因为您可以访问您的文件系统并在其中操作可用的数据……幸运的是,您尝试做的事情是不可能的。
如果您需要访问本地资源,您可以尝试在您的计算机上启动一个Web服务器,在这种情况下,您的方法将起作用。其他解决方法也是可行的,例如对Chrome设置进行操作,但我总是更喜欢使用干净的方式,安装一个本地Web服务器,也许是在不同的端口上(不,这并不难!)。
另请参阅:

1
规则的原因更多是社会性的而非技术性的;浏览器已经很好地防止了对跨域资源的编程访问(例如SOP、CDN脚本、深度链接的IMG标签等),但即使脚本无法确定它正在显示什么,人们在浏览器窗口中看到他们的本地内容仍然会感到不安。 - dandavis
1
@dandavis 是的,你说得对,但我认为防止这种情况发生是有好处的。除了一些实现中的错误(如果您无法打开本地资源,则可能更安全),还可能存在一些特定的场景,其他人正在查看您的屏幕(屏幕共享应用程序,或者只是在您的办公室背后),您不希望您的图像(可能是信用卡或私人图像)可以通过访问某些网站来打开,这些网站可以猜测您本地文件系统上的位置... - Prak

1
这是关于Google Chrome 扩展程序的。
const url = "file:///C:\002.jpg"
chrome.tabs.create({url, active:true})

manifest.json

{
  "name": "",
  "manifest_version": 3,
  "permissions": [
    "activeTab",
    "tabs"
  ],
  // ...
}


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