页面静态化的应用

什么是页面静态化

课程预览功能通过模板引擎技术在页面模板中填充数据,生成html页面,这个过程是当客户端请求服务器时服务器才开始渲染生成html页面,最后响应给浏览器,服务端渲染的并发能力是有限的。

页面静态化则强调将生成html页面的过程提前,提前使用模板引擎技术生成html页面,当客户端请求时直接请求html页面,由于是静态页面可以使用nginx、apache等高性能的web服务器,并发性能高。

什么时候用页面静态化技术

当数据变化不频繁,一旦生成静态页面很长一段时间内很少变化,此时可以使用页面静态化。因为如果数据变化频繁,一旦改变就需要重新生成静态页面,导致维护静态页面的工作量很大。

根据课程发布的业务需求,虽然课程发布后仍可以修改课程信息,但需要经过课程审核,且修改频度不大,所以适合使用页面静态化。

项目使用静态化技术的整体说明。

我们使用代码将页面进行静态化之后存储在minio然后我们访问指定域名就能够访问到我们minio中的静态页面

Nginx中的conf文件设置

#访问minio文件系统的网址
    upstream fileserver{
    server 192.168.101.65:9000 weight=10;
    } 

server {
        listen         80;
        server_name  file.51xuecheng.cn;
        #charset koi8-r;
        ssi on;
        ssi_silent_errors on;
        #access_log  logs/host.access.log  main;
        location /video {
            proxy_pass   http://fileserver;
        }

        location /mediafiles {
            proxy_pass   http://fileserver;
        }
   }

这样我们可以直接访问 http://192.168.101.65:9000/mediafiles/course/test.html或者我们可以访问域名file.51xuecheng.cn/mediafiles/course/test.html这样Nginx就会自动代理到我们要访问的文件了。

页面静态化测试代码

@SpringBootTest(classes = XuechengPlusContentServiceApplication.class)
public class FreemarkerTest {

    @Autowired
    CoursePublishService coursePublishService;
    //测试页面静态化
    @Test
    public void testGenerateHtmlByTemplate() throws IOException, TemplateException {
        //配置freemarker
        Configuration configuration = new Configuration(Configuration.getVersion());

        //加载模板
        //选指定模板路径,classpath下templates下
        //得到classpath路径
        String classpath = this.getClass().getResource("/").getPath();
        configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));
        //设置字符编码
        configuration.setDefaultEncoding("utf-8");

        //指定模板文件名称
        Template template = configuration.getTemplate("course_template.ftl");

        //准备数据
        CoursePreviewDto coursePreviewInfo = coursePublishService.getCoursePreviewInfo(2L);

        Map map = new HashMap<>();
        map.put("model", coursePreviewInfo);

        //静态化
        //参数1:模板,参数2:数据模型
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        System.out.println(content);
        //将静态化内容输出到文件中
        InputStream inputStream = IOUtils.toInputStream(content);
        //输出流
        FileOutputStream outputStream = new FileOutputStream("D:\\upload\\test.html");
        IOUtils.copy(inputStream, outputStream);

    }

}

将本地生成的静态页面上传到minio

我们现在是在一个content微服务中,我们需要调用media微服务,并且这两个微服务互相是独立的,(注意我们content内部的api service model微服务具有相互依赖关系这样我们的就可以直接使用里面的东西)独立的微服务之间相互访问要使用feign进行,下面对feign进行配置。

发送请求的接口类

@FeignClient(value = "media-api",configuration = MultipartSupportConfig.class)
public interface MediaServiceClient {

    @RequestMapping(value = "/media/upload/coursefile",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String uploadFile(@RequestPart("filedata") MultipartFile upload,@RequestParam(value = "objectName",required=false) String objectName);
}

 启动类使用注解

@EnableFeignClients(basePackages={"com.xuecheng.content.feignclient"})

feignClient调用

@SpringBootTest(classes = XuechengPlusContentServiceApplication.class)
public class FeignUploadTest {

    @Autowired
    MediaServiceClient mediaServiceClient;

    //远程调用,上传文件
    @Test
    public void test() {
        MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(new File("D:\\upload\\test.html"));
        mediaServiceClient.uploadFile(multipartFile,"course/test.html");
    }

}

最终上传完文件,之后就直接访问之前的域名即可访问我们minio中存储的静态页面。

注意:
feign本身是不支持文件格式的传递参数,要使用要进行配置

坐标


    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery



    org.springframework.cloud
    spring-cloud-starter-openfeign


    io.github.openfeign
    feign-httpclient



    io.github.openfeign.form
    feign-form
    3.8.0


    io.github.openfeign.form
    feign-form-spring
    3.8.0

 配置

feign:
  hystrix:
    enabled: true
  circuitbreaker:
    enabled: true
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000  #熔断超时时间
ribbon:
  ConnectTimeout: 60000 #连接超时时间
  ReadTimeout: 60000 #读超时时间
  MaxAutoRetries: 0 #重试次数
  MaxAutoRetriesNextServer: 1 #切换实例的重试次数

配置feign支持Multipart 在config包下面类

package com.xuecheng.content.config;

import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;

/**
 * @author Mr.M
 * @version 1.0
 * @description TODO
 * @date 2022/10/15 22:13
 */
@Configuration
public class MultipartSupportConfig {

    @Autowired
    private ObjectFactory messageConverters;

    @Bean
    @Primary//注入相同类型的bean时优先使用
    @Scope("prototype")
    public Encoder feignEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    //将file转为Multipart
    public static MultipartFile getMultipartFile(File file) {
        FileItem item = new DiskFileItemFactory().createItem("file", MediaType.MULTIPART_FORM_DATA_VALUE, true, file.getName());
        try (FileInputStream inputStream = new FileInputStream(file);
             OutputStream outputStream = item.getOutputStream();) {
            IOUtils.copy(inputStream, outputStream);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return new CommonsMultipartFile(item);
    }
}

 注意:

直接访问 http://192.168.101.65:9000/mediafiles/course/test.html或者我们可以访问域名file.51xuecheng.cn/mediafiles/course/test.html这样Nginx就会自动代理到我们要访问的文件了。

但是大家看我上面的Nginx配置,我们的域名下的虚拟主机并没有访问我们静态样式文件的接口,这些接口都在我们www.51xuecheng.cn这个域名下面,因此要通过这个域名访问我们的minio中的文件,在这个域名下加上 就会代理到我们的minio

location /course/ {  
        proxy_pass http://fileserver/mediafiles/course/;
        } 

 整体Nginx配置如下·


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;
    #访问minio文件系统的网址
    upstream fileserver{
    server 192.168.101.65:9000 weight=10;
    } 
       #后台网关
    upstream gatewayserver{
    server 127.0.0.1:63010 weight=10;
    }
    server {
        listen       80;
        server_name  www.51xuecheng.cn localhost;
        #rewrite ^(.*) https://$server_name$1 permanent;
        #charset koi8-r;
        ssi on;
        ssi_silent_errors on;
        #access_log  logs/host.access.log  main;

        location / {
            alias   E:/code/xc-ui-pc-static-portal/;
            index  index.html index.htm;
        }
        #静态资源
        location /static/img/ {  
                alias  E:/code/xc-ui-pc-static-portal/img/;
        } 
        location /static/css/ {  
                alias   E:/code/xc-ui-pc-static-portal/css/;
        } 
        location /static/js/ {  
                alias   E:/code/xc-ui-pc-static-portal/js/;
        } 
        location /static/plugins/ {  
                alias   E:/code/xc-ui-pc-static-portal/plugins/;
                add_header Access-Control-Allow-Origin http://ucenter.51xuecheng.cn;  
                add_header Access-Control-Allow-Credentials true;  
                add_header Access-Control-Allow-Methods GET;
        } 
        location /plugins/ {  
                alias   E:/code/xc-ui-pc-static-portal/plugins/;
        } 
        location /course/preview/learning.html {
                alias E:/code/xc-ui-pc-static-portal/course/learning.html;
        } 
        location /course/search.html {  
                root   E:/code/xc-ui-pc-static-portal;
        } 
        location /course/learning.html {  
                root   E:/code/xc-ui-pc-static-portal;
        } 
        #api
        location /api/ {
                proxy_pass http://gatewayserver/;
        }
        #openapi 这里不走网关 
        location /open/content/ {
            proxy_pass http://gatewayserver/content/open/;
        } 
        location /open/media/ {
            proxy_pass http://gatewayserver/media/open/;
        }
        location /course/ {  
        proxy_pass http://fileserver/mediafiles/course/;
        } 

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }
    server {
        listen         80;
        server_name  file.51xuecheng.cn;
        #charset koi8-r;
        ssi on;
        ssi_silent_errors on;
        #access_log  logs/host.access.log  main;
        location /video {
            proxy_pass   http://fileserver;
        }

        location /mediafiles {
            proxy_pass   http://fileserver;
        }
   }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
 

 之后我们访问www.51xuecheng.cn/course/test.html

你可能感兴趣的:(服务器,前端,运维)