Vue 发送 PDF 文件链接到 WinForm 程序进行打印

Vue 发送 PDF 文件链接到 WinForm 程序进行打印的完整流程如下:

1. Vue 端

Vue 通过 fetchaxios 发送 PDF 文件的 URL 给 WinForms 程序(WinForms 需要开启一个本地 API)。

vue 复制代码
<template>
  <div>
    <button @click="sendPrintRequest">打印PDF</button>
  </div>
</template>

<script>
import axios from "axios";

export default {
  methods: {
    sendPrintRequest() {
      const pdfUrl = "http://yourserver.com/sample.pdf"; // 你的 PDF 地址
      axios
        .post("http://localhost:5000/print", { pdfUrl }) // 本地 WinForms 监听的 API
        .then((response) => {
          console.log("打印请求成功", response.data);
        })
        .catch((error) => {
          console.error("打印请求失败", error);
        });
    },
  },
};
</script>

2. WinForm 后端

WinForms 需要开启一个本地 HTTP 服务器,用于接收 Vue 发送的 PDF 链接,并调用本地打印机打印。

1) 创建一个 Web API

使用 HttpListener 监听 http://localhost:5000/print,并接收 Vue 发送的 JSON 数据。

csharp 复制代码
using System;
using System.Drawing.Printing;
using System.IO;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Diagnostics;

class Program
{
    static void Main()
    {
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:5000/"); // 监听本地端口
        listener.Start();
        Console.WriteLine("打印服务器已启动...");

        while (true)
        {
            HttpListenerContext context = listener.GetContext();
            Task.Run(() => HandleRequest(context));
        }
    }

    static async void HandleRequest(HttpListenerContext context)
    {
        HttpListenerRequest request = context.Request;
        HttpListenerResponse response = context.Response;

        if (request.HttpMethod == "POST" && request.Url.AbsolutePath == "/print")
        {
            using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
            {
                string requestBody = await reader.ReadToEndAsync();
                var data = JsonSerializer.Deserialize<PrintRequest>(requestBody);

                if (data != null && !string.IsNullOrEmpty(data.PdfUrl))
                {
                    Console.WriteLine("收到打印请求:" + data.PdfUrl);

                    bool success = PrintPdf(data.PdfUrl);

                    response.StatusCode = success ? 200 : 500;
                    string responseText = success ? "打印成功" : "打印失败";
                    byte[] buffer = Encoding.UTF8.GetBytes(responseText);
                    response.OutputStream.Write(buffer, 0, buffer.Length);
                }
            }
        }

        response.Close();
    }

    static bool PrintPdf(string pdfUrl)
    {
        try
        {
            string localPath = Path.Combine(Path.GetTempPath(), "temp.pdf");

            using (WebClient client = new WebClient())
            {
                client.DownloadFile(pdfUrl, localPath);
            }

            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = localPath,
                Verb = "print",
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden
            };
            Process.Start(psi);

            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("打印出错:" + ex.Message);
            return false;
        }
    }

    class PrintRequest
    {
        public string PdfUrl { get; set; }
    }
}
2) Aspose.Pdf 插件打印

复杂一点的,使用Aspose.Pdf打印插件进行答应

csharp 复制代码
using Aspose.Pdf;
using PdfiumViewer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Printing;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace ConsoleApp1
{
    /// <summary>
    /// VUE发送PDF文件到客户端 客户端调用默认打印机 开始打印
    /// </summary>
    public class VueToPrintHelper
    {
        public VueToPrintHelper()
        {
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:5066/");
            listener.Start();
            Console.WriteLine("Listening for requests...");

            // 获取所有已安装的打印机
            foreach (string printer in PrinterSettings.InstalledPrinters)
            {
                Console.WriteLine(printer);
            }

            while (true)
            {
                HttpListenerContext context = listener.GetContext();
                Task.Run(() => HandleRequest(context));
            }
        }

        static async void HandleRequest(HttpListenerContext context)
        {
            HttpListenerRequest request = context.Request;
            HttpListenerResponse response = context.Response;

            // 设置 CORS 头部,允许前端访问
            response.AddHeader("Access-Control-Allow-Origin", "*");
            response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
            response.AddHeader("Access-Control-Allow-Headers", "Content-Type");

            // 处理 OPTIONS 预检请求 (CORS 预检)
            if (request.HttpMethod == "OPTIONS")
            {
                response.StatusCode = 200;
                response.Close();
                return;
            }

            if (request.HttpMethod == "POST" && request.Url.AbsolutePath == "/print")
            {
                using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
                {
                    string requestBody = await reader.ReadToEndAsync();
                    var data = JsonSerializer.Deserialize<PrintRequest>(requestBody);

                    if (data != null && !string.IsNullOrEmpty(data.PdfUrl))
                    {
                        Console.WriteLine("收到打印请求:" + data.PdfUrl);

                        bool success = PrintPdf(data.PdfUrl);

                        response.StatusCode = success ? 200 : 500;
                        string responseText = success ? "打印成功" : "打印失败";
                        byte[] buffer = Encoding.UTF8.GetBytes(responseText);
                        response.OutputStream.Write(buffer, 0, buffer.Length);
                    }
                }
            }

            response.Close();
        }

        static bool PrintPdf(string pdfUrl)
        {
            try
            {
                var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "print_pdfs");
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
                string localPath = Path.Combine(filePath, Path.GetFileName(pdfUrl));

                if (!File.Exists(localPath))
                {
                    using (WebClient client = new WebClient())
                    {
                        client.DownloadFile(pdfUrl, localPath);
                    }
                }

                PrintPdf3(localPath);
                Console.WriteLine("打印命令已发送");

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("打印出错:" + ex.Message);
                return false;
            }
        }

        static string DownloadPdf(string pdfUrl)
        {
            string tempFilePath = Path.Combine(Path.GetTempPath(), "document.pdf");

            using (WebClient client = new WebClient())
            {
                try
                {
                    client.DownloadFile(pdfUrl, tempFilePath);
                    return tempFilePath;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error downloading PDF: " + ex.Message);
                    return null;
                }
            }
        }

        static void PrintPDF(string filePath)
        {
            using (var document = PdfDocument.Load(filePath)) // 使用 PdfiumViewer 加载 PDF
            {
                PrintDocument printDocument = document.CreatePrintDocument();
                printDocument.Print();
            }
        }

        static void PrintPDF2(string filePath)
        {
            ProcessStartInfo psi = new ProcessStartInfo
            {
                FileName = filePath,  // 这里直接是 PDF 文件
                Verb = "print",      // 使用默认应用程序打印
                UseShellExecute = true, // 关键:让 Windows 自动用默认应用打开
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden
            };
            Process.Start(psi);
        }

        static void PrintPdf3(string pdfPath)
        {
            // 加载 PDF 文档
            Document pdfDocument = new Document(pdfPath);

            // 创建 PdfViewer 实例
            using (Aspose.Pdf.Facades.PdfViewer pdfViewer = new Aspose.Pdf.Facades.PdfViewer(pdfDocument))
            {
                pdfViewer.AutoResize = true;   // 自动调整大小
                pdfViewer.AutoRotate = true;   // 自动旋转
                pdfViewer.PrintPageDialog = false; // 不弹出打印对话框

                // 设置打印机
                Aspose.Pdf.Printing.PrinterSettings printerSettings = new Aspose.Pdf.Printing.PrinterSettings();
                printerSettings.PrinterName = PrinterSettings.InstalledPrinters[0]; // 选择默认打印机

                // 创建 PageSettings 并绑定 PrinterSettings
                Aspose.Pdf.Printing.PageSettings pageSettings = new Aspose.Pdf.Printing.PageSettings();
                pageSettings.PrinterSettings = printerSettings;

                // 进行打印
                pdfViewer.PrintDocumentWithSettings(pageSettings, printerSettings);
            }

            Console.WriteLine("✅ PDF 已发送到打印机!");
        }
    }

    class PrintRequest
    {
        public string PdfUrl { get; set; }
    }
}

3. 测试流程

  1. 运行 WinForms 程序 ,它会监听 http://localhost:5000/print
  2. Vue 页面点击按钮,发送 PDF URL 进行打印。
  3. WinForms 下载 PDF 并调用本地打印机 进行打印。

这种方式适用于局域网环境,Vue 只需要调用本地的 WinForms 服务器即可,不涉及复杂的文件传输流程。🎯

请求变成 OPTIONS,通常是由于 CORS 预检请求 (Preflight Request)。当你从 Vue (浏览器) 发送 POST 请求到 http://localhost:5000/print,而此 API 位于 不同的端口 ,浏览器会先发送一个 OPTIONS 请求来检查服务器是否允许跨域访问。


解决方案

你需要在 WinForms API (C#) 中处理 OPTIONS 请求,返回适当的 CORS 头部,让浏览器允许跨域请求。

修改 C# 代码

HandleRequest 方法中添加对 OPTIONS 请求的处理:

csharp 复制代码
static async void HandleRequest(HttpListenerContext context)
{
    HttpListenerRequest request = context.Request;
    HttpListenerResponse response = context.Response;

    // 处理 OPTIONS 预检请求 (CORS 预检)
    if (request.HttpMethod == "OPTIONS")
    {
        response.AddHeader("Access-Control-Allow-Origin", "*");
        response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        response.AddHeader("Access-Control-Allow-Headers", "Content-Type");
        response.StatusCode = 200;
        response.Close();
        return;
    }

    if (request.HttpMethod == "POST" && request.Url.AbsolutePath == "/print")
    {
        using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
        {
            string requestBody = await reader.ReadToEndAsync();
            var data = JsonSerializer.Deserialize<PrintRequest>(requestBody);

            if (data != null && !string.IsNullOrEmpty(data.PdfUrl))
            {
                Console.WriteLine("收到打印请求:" + data.PdfUrl);

                bool success = PrintPdf(data.PdfUrl);

                response.StatusCode = success ? 200 : 500;
                string responseText = success ? "打印成功" : "打印失败";
                byte[] buffer = Encoding.UTF8.GetBytes(responseText);
                response.OutputStream.Write(buffer, 0, buffer.Length);
            }
        }
    }

    // 添加 CORS 头部 (允许跨域请求)
    response.AddHeader("Access-Control-Allow-Origin", "*");
    response.Close();
}

解释

  1. CORS 预检请求 (OPTIONS) 处理

    • OPTIONS 请求是浏览器在 跨域请求 时自动发送的,用于检查服务器是否允许这个请求。
    • Access-Control-Allow-Origin: * 允许来自任何域的请求。
    • Access-Control-Allow-Methods: POST, GET, OPTIONS 允许前端发送 POST 请求。
    • Access-Control-Allow-Headers: Content-Type 允许发送 JSON 数据。
  2. 添加 CORS 头部

    • POST 处理完成后,仍然需要 返回 Access-Control-Allow-Origin: *,否则浏览器可能仍然拒绝请求。

Vue 端 (可选优化)

你也可以在 Vue 端的 axios 请求中 显式添加 Content-Type ,避免某些情况下触发 OPTIONS 预检请求:

javascript 复制代码
axios.post("http://localhost:5000/print", 
  { pdfUrl: "http://yourserver.com/sample.pdf" },
  {
    headers: { "Content-Type": "application/json" }
  }
);

最终效果

  1. WinForms API 允许跨域请求 ,不会再被 OPTIONS 请求阻挡。
  2. Vue 可以正常发送 POST 请求,WinForms API 正常接收并打印 PDF 🎉。

这样,Vue 和 WinForm 端的通信就能顺利进行了!🚀

相关推荐
d3soft1 小时前
deepseek清华大学第二版 如何获取 DeepSeek如何赋能职场应用 PDF文档 电子档(附下载)
ai·pdf·教程·deepseek·赋能职场
hello_simon1 小时前
【Word转PDF】在线Doc/Docx转换为PDF格式 免费在线转换 功能强大好用
职场和发展·pdf·word·学习方法·word转pdf·石墨文档·word转换
anyup_前端梦工厂2 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
前端御书房2 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169542 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
风口上的猪20153 小时前
thingboard告警信息格式美化
java·服务器·前端
程序员黄同学3 小时前
请谈谈 Vue 中的响应式原理,如何实现?
前端·javascript·vue.js
快乐的二进制鸭4 小时前
uniapp实现app的pdf预览
pdf·uni-app
爱编程的小庄4 小时前
web网络安全:SQL 注入攻击
前端·sql·web安全
宁波阿成5 小时前
vue3里组件的v-model:value与v-model的区别
前端·javascript·vue.js