背景 在瀏覽器中訪問本地靜態資源html網頁時,可能會遇到跨域問題如圖。 是因為瀏覽器預設啟用了同源策略,即只允許載入與當前網頁具有相同源(協議、功能變數名稱和埠)的內容。 WebView2預設情況下啟用了瀏覽器的同源策略,即只允許載入與主機相同源的內容。所以如果我們把靜態資源發佈到iis或者通過node ...
背景
在瀏覽器中訪問本地靜態資源html網頁時,可能會遇到跨域問題如圖。
是因為瀏覽器預設啟用了同源策略,即只允許載入與當前網頁具有相同源(協議、功能變數名稱和埠)的內容。
WebView2預設情況下啟用了瀏覽器的同源策略,即只允許載入與主機相同源的內容。所以如果我們把靜態資源發佈到iis或者通過node進行啟動就可以看到不跨域了。
解決方案
-
使用CORS(Cross-Origin Resource Sharing):如果你有控制伺服器端,可以在伺服器端配置CORS來允許跨域請求。在伺服器端的響應頭中添加相關的CORS頭部信息,例如允許訪問的功能變數名稱、請求方法等,以允許JavaScript跨域訪問。
- 使用WebView2的
AddWebResourceRequestedFilter
方法:通過添加Web資源請求過濾器,你可以攔截WebView2控制項中載入的資源請求,併進行處理。在攔截到JavaScript文件請求時,修改響應頭部信息,添加Access-Control-Allow-Origin
頭部來解決跨域問題。 - 使用代理伺服器:你可以在本地啟動一個代理伺服器,將WebView2控制項的請求轉發到代理伺服器上,然後代理伺服器再將請求發送到原始伺服器並返迴響應。在代理伺服器上你可以設置合適的CORS頭部信息來解決跨域問題。
思路
-
首先,確保你已經安裝了
Microsoft.Web.WebView2
。你可以在Visual Studio的NuGet包管理器中搜索並安裝此包。 - 然後通過HttpListener進行文件夾的靜態資源進行代理髮布
- 然後通過webview2進行導航訪問即可我們會發現跨域問題已經解決
代碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WinApp.View { public partial class Cors : Form { // 創建HttpListener對象並指定綁定的埠 HttpListener _listener; string _folderPath; string _rootDirectory; public Cors() { InitializeComponent(); // 初始化 InitializeAsync(); } private async void InitializeAsync() { // 獲取本地靜態資源的路徑 _rootDirectory = AppDomain.CurrentDomain.BaseDirectory + "offline-exam-player"; //設置本地離線播放器為代理服務 _rootDirectory = @"C:\Users\admin\Documents\WeChat Files\wxid_1ofgk575ybpt22\FileStorage\File\2024-02\ng-alain8\ng-alain8/"; _folderPath = @"C:\Users\admin\Documents\WeChat Files\wxid_1ofgk575ybpt22\FileStorage\File\2024-02\ng-alain8\ng-alain8/index.html"; _listener = new HttpListener(); // 設置代理伺服器的監聽地址和埠號 _listener.Prefixes.Add("http://localhost:8080/"); _listener.Start(); // 啟動代理伺服器 Task.Run(() => { // 啟動代理伺服器 ProcessRequests(); }); // 停止代理伺服器(這裡演示就不停止了) //server.Stop(); } private void ProcessRequests() { try { while (_listener.IsListening) { HttpListenerContext context = _listener.GetContext(); string requestPath = context.Request.Url.AbsolutePath; string filePath = _rootDirectory + requestPath; // Serve the requested file if it exists if (System.IO.File.Exists(filePath)) { string extension = System.IO.Path.GetExtension(filePath); string contentType; switch (extension) { case ".html": contentType = "text/html"; break; case ".js": contentType = "application/javascript"; break; case ".less": case ".css": contentType = "text/css"; break; case ".svg": contentType = "image/svg+xml"; break; default: contentType = "application/octet-stream"; break; } context.Response.ContentType = contentType; //context.Response.ContentType = "text/html"; byte[] responseBuffer = System.IO.File.ReadAllBytes(filePath); context.Response.OutputStream.Write(responseBuffer, 0, responseBuffer.Length); context.Response.Close(); } else { // Return a 404 response if the file does not exist context.Response.StatusCode = 404; context.Response.Close(); } } } catch (Exception ex) { // Handle any exceptions that may occur Console.WriteLine(ex.ToString()); } } private async void Cors_Load(object sender, EventArgs e) { //本地靜態資源,直接訪問會出現跨院,如果通過iis訪問則不會跨域; // 確保CoreWebView2運行時已準備就緒 await webView21.EnsureCoreWebView2Async(); // 在WebView2控制項中載入URL //webView21.CoreWebView2.Navigate(_folderPath); webView21.CoreWebView2.Navigate("http://localhost:8080/" + "index.html"); } } }
代理服務幫助類代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace WinApp.Until { public class ProxyHelper { private readonly HttpListener _listener; private readonly string _rootDirectory; /// <summary> /// 實例化 /// </summary> /// <param name="serviceIp">代理的ip地址帶埠,例子:http://localhost:8080/ </param> /// <param name="folderPath">需要代理的文件夾,例子:AppDomain.CurrentDomain.BaseDirectory + "offline-exam-player" </param> public ProxyHelper(string serviceIp, string folderPath) { _rootDirectory = folderPath; _listener = new HttpListener(); _listener.Prefixes.Add(serviceIp); } public async Task Start() { _listener.Start(); await Task.Run(() => ProcessRequests()); } public void Stop() { _listener.Stop(); _listener.Close(); Console.WriteLine("Proxy server stopped."); } private void ProcessRequests() { try { while (_listener.IsListening) { HttpListenerContext context = _listener.GetContext(); string requestPath = context.Request.Url.AbsolutePath; string filePath = _rootDirectory + requestPath; // Serve the requested file if it exists if (System.IO.File.Exists(filePath)) { string extension = System.IO.Path.GetExtension(filePath); string contentType; switch (extension) { case ".html": contentType = "text/html"; break; case ".js": contentType = "application/javascript"; break; case ".less": case ".css": contentType = "text/css"; break; case ".svg": contentType = "image/svg+xml"; break; default: contentType = "application/octet-stream"; break; } context.Response.ContentType = contentType; //context.Response.ContentType = "text/html"; byte[] responseBuffer = System.IO.File.ReadAllBytes(filePath); context.Response.OutputStream.Write(responseBuffer, 0, responseBuffer.Length); context.Response.Close(); } else { // Return a 404 response if the file does not exist context.Response.StatusCode = 404; context.Response.Close(); } } } catch (Exception ex) { // Handle any exceptions that may occur Console.WriteLine(ex.ToString()); } } } }
結語
最後如果對於不多的跨域js文件,可以把js的代碼內嵌到index.html頁面實現。就是<script>跨域js內容</script>
從前慢,車馬慢。 一生只愛一個人。