{ "version": "https://jsonfeed.org/version/1", "title": "涛声依旧", "subtitle": "天下事有难易乎?为之,则难者亦易矣", "icon": "https://hitoli.com/images/favicon.ico", "description": "天生我材必有用", "home_page_url": "https://hitoli.com", "items": [ { "id": "https://hitoli.com/2023/02/18/%E4%BF%AE%E6%94%B9IntellIJ-IDE%E8%83%8C%E6%99%AF%E8%89%B2%E5%92%8C%E5%AD%97%E4%BD%93%E5%A4%A7%E5%B0%8F/", "url": "https://hitoli.com/2023/02/18/%E4%BF%AE%E6%94%B9IntellIJ-IDE%E8%83%8C%E6%99%AF%E8%89%B2%E5%92%8C%E5%AD%97%E4%BD%93%E5%A4%A7%E5%B0%8F/", "title": "修改IntellIJ IDE背景色和字体大小", "date_published": "2023-02-18T09:42:00.000Z", "content_html": "

# 引言

\n

网上搜索了几个修改 IDE 背景色和字体大小的方法,记录一下方便以后查看。

\n

# 操作截图

\n
    \n
  1. \n

    修改代码区颜色
    \n\"bb050e7e4c3b3ff2968b0a1be311d31f.png\"

    \n
  2. \n
  3. \n

    修改代码区字体大小
    \n\"af92e69249a74978f56a5b2f8bf792a8.png\"

    \n
  4. \n
  5. \n

    修改控制台背景色
    \n\"80dd5d82bfc6d0380ce34a590d8beeb4.png\"

    \n
  6. \n
  7. \n

    修改控制台字体大小
    \n\"86bd97d1937b77faa27d31db7c2abb91.png\"

    \n
  8. \n
  9. \n

    修改左侧背景色
    \n\"4875f8006144733c0e6710a2b04bc2be.jpg\"

    \n
  10. \n
\n", "tags": [ "工作", "解决问题", "IDE", "IDE", "intellIJ" ] }, { "id": "https://hitoli.com/2023/01/31/KLineChart%E7%94%BB%E6%B3%A2%E6%AE%B5%E9%AB%98%E4%BD%8E%E4%BB%B7%E5%9B%BE/", "url": "https://hitoli.com/2023/01/31/KLineChart%E7%94%BB%E6%B3%A2%E6%AE%B5%E9%AB%98%E4%BD%8E%E4%BB%B7%E5%9B%BE/", "title": "KLineChart画波段高低价图", "date_published": "2023-01-31T01:44:00.000Z", "content_html": "

# 引言

\n

使用指定数据方式得到的线条总是不能达到想要的效果,一是阶梯线在价格发生变化的点存在倾斜,二是高低价的线很难完美显示,所以只能自己动手画了。代码仅供参考,如有错误的地方请指正!
\n\"ee3c75b472c5869794e205747703d888.png\"

\n

# 模版代码

\n
this.chart.addTechnicalIndicatorTemplate({
\tname: 'BandHighLowInd',
    shortName: '波段高低价',
    calcParams: [{ value: 10 }],
    precision: 2,
    plots: [
      { key: 'high', title: '高: ', color: (data, options) => { return options.line.colors[0] } },
      { key: 'low', title: '低: ', color: (data, options) => { return options.line.colors[1] } },
      { key: 'highLow', title: '高低: ', color: (data, options) => { return options.line.colors[2] } }
    ],
    calcTechnicalIndicator: (dataList, { params }) => {
      let compareKlineSize = params[0] // 取前后 k 的范围
      let highs = []
      let lows = []
      let highLows = []
      let findHigh // 高低价当前查找标识
      dataList.forEach(function (kLineData, i) {
        let frontIndex = i - compareKlineSize
        if (frontIndex <= 0) {
          frontIndex = 0
        }
        let frontDatas = []
        if (frontIndex < i) {
          frontDatas = dataList.slice(frontIndex, i)
        }
        let afterIndex = i + compareKlineSize + 1
        let afterDatas = []
        if (i < dataList.length - 1) {
          afterDatas = dataList.slice(i + 1, afterIndex)
        }
        if (frontDatas.length === compareKlineSize && afterDatas.length === compareKlineSize) { // 前后 K 线数据必须都找到要比较的条数
          let high = null
          let low = null
          frontDatas.concat(afterDatas).forEach(function (kLineData, i) { // 找出前后 k 线中的最高和最低价
            if (high === null || kLineData.high > high) {
              high = kLineData.high
            }
            if (low === null || kLineData.low < low) {
              low = kLineData.low
            }
          })
          if (kLineData.high > high) { // 当前 k 的高大于前后 k 中找出的高,则放入高价集合中
            highs.push({
              time: kLineData.timestamp,
              value: kLineData.high,
              index: i
            })
            if (isNotEmpty(findHigh)) {
              if (findHigh && highLows[highLows.length - 1].value !== kLineData.high) {
                highLows.push({
                  time: kLineData.timestamp,
                  value: kLineData.high,
                  index: i
                })
                findHigh = false
              }
            } else {
              highLows.push({
                time: kLineData.timestamp,
                value: kLineData.high,
                index: i
              })
              findHigh = false
            }
          }
          if (kLineData.low < low) { // 当前 k 的低小于前后 k 中找出的低,则放入低价集合中
            lows.push({
              time: kLineData.timestamp,
              value: kLineData.low,
              index: i
            })
            if (isNotEmpty(findHigh)) {
              if (!findHigh && highLows[highLows.length - 1].value !== kLineData.low) {
                highLows.push({
                  time: kLineData.timestamp,
                  value: kLineData.low,
                  index: i
                })
                findHigh = true
              }
            } else {
              highLows.push({
                time: kLineData.timestamp,
                value: kLineData.low,
                index: i
              })
              findHigh = true
            }
          }
        }
      })
      let high, low, highLow
      return dataList.map((kLineData, i) => {
        let item = {
        }
        highs.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            high = data.value
            item.highOrigin = true
          }
        })
        if (isNotEmpty(high)) { // 持续先前的高,画出阶梯线
          item.timestamp = kLineData.timestamp
          item.high = high
        }
        lows.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            low = data.value
            item.lowOrigin = true
          }
        })
        if (isNotEmpty(low)) { // 持续先前的低,画出阶梯线
          item.timestamp = kLineData.timestamp
          item.low = low
        }
        highLows.forEach((data) => {
          if (kLineData.timestamp === data.time) {
            highLow = data.value
            item.highLowOrigin = true
          }
        })
        if (isNotEmpty(highLow)) { // 持续先前的高低,方便 title 显示
          item.timestamp = kLineData.timestamp
          item.highLow = highLow
        }
        return item
      })
    },
    render: ({ ctx, dataSource, viewport, styles, xAxis, yAxis }) => {
      if (dataSource.technicalIndicatorDataList.length <= 0) {
        return
      }
      let x = xAxis.convertToPixel(0)
      let high, low, highLow, highLowX
      dataSource.technicalIndicatorDataList.forEach(function (data, i) {
        // 画高线
        ctx.textBaseline = 'middle'
        ctx.textAlign = 'center'
        ctx.fillStyle = '#fff'
        ctx.strokeStyle = '#fff'
        if (styles.line && styles.line.colors && styles.line.colors[0]) {
          ctx.fillStyle = styles.line.colors[0]
          ctx.strokeStyle = styles.line.colors[0]
        }
        if (isNotEmpty(high) && data.high !== high) {
          ctx.beginPath()
          ctx.moveTo(x, yAxis.convertToPixel(high))
          ctx.lineTo(x, yAxis.convertToPixel(data.high))
          ctx.stroke()
          ctx.closePath()
        }
        high = data.high
        let y = yAxis.convertToPixel(high)
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.lineTo(x + viewport.dataSpace, y)
        ctx.stroke()
        ctx.closePath()
        // 画低线
        ctx.fillStyle = '#fff'
        ctx.strokeStyle = '#fff'
        if (styles.line && styles.line.colors && styles.line.colors[1]) {
          ctx.fillStyle = styles.line.colors[1]
          ctx.strokeStyle = styles.line.colors[1]
        }
        if (isNotEmpty(low) && data.low !== low) {
          ctx.beginPath()
          ctx.moveTo(x, yAxis.convertToPixel(low))
          ctx.lineTo(x, yAxis.convertToPixel(data.low))
          ctx.stroke()
          ctx.closePath()
        }
        low = data.low
        y = yAxis.convertToPixel(low)
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.lineTo(x + viewport.dataSpace, y)
        ctx.stroke()
        ctx.closePath()
        // 画高低线
        if (isNotEmpty(data.highLow) && data.highLowOrigin === true) {
          if (isNotEmpty(highLow) && isNotEmpty(highLowX)) {
            ctx.fillStyle = '#fff'
            ctx.strokeStyle = '#fff'
            if (styles.line && styles.line.colors && styles.line.colors[2]) {
              ctx.fillStyle = styles.line.colors[2]
              ctx.strokeStyle = styles.line.colors[2]
            }
            ctx.beginPath()
            ctx.moveTo(highLowX, yAxis.convertToPixel(highLow))
            ctx.lineTo(x, yAxis.convertToPixel(data.highLow))
            ctx.stroke()
            ctx.closePath()
          }
          highLow = data.highLow
          highLowX = x
        }
        // 画价格
        if (data.high !== undefined && data.highOrigin === true) { // 画高价
          let text = Number.parseFloat(data.high).toFixed(2)
          ctx.fillStyle = '#fff'
          if (styles.line && styles.line.colors && styles.line.colors[0]) {
            ctx.fillStyle = styles.line.colors[0]
          }
          let offset = 10
          let y = yAxis.convertToPixel(data.high)
          for (let i = 2; i < offset - 1; i += 2) {
            ctx.fillText('.', x, y - i)
          }
          ctx.fillText(text, x, y - offset)
        }
        if (data.low !== undefined && data.lowOrigin === true) { // 画低价
          let text = Number.parseFloat(data.low).toFixed(2)
          ctx.fillStyle = '#fff'
          if (styles.line && styles.line.colors && styles.line.colors[1]) {
            ctx.fillStyle = styles.line.colors[1]
          }
          let offset = 15
          let y = yAxis.convertToPixel(data.low)
          for (let i = 2; i < offset - 5; i += 2) {
            ctx.fillText('.', x, y + i)
          }
          ctx.fillText(text, x, y + offset)
        }
        x += viewport.dataSpace
      })
    }
})
", "tags": [ "工作", "解决问题", "KLineChart", "KLineChart", "K线", "自定义指标" ] }, { "id": "https://hitoli.com/2023/01/10/Vue%E6%A0%B9%E6%8D%AE%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82%E4%BF%AE%E6%94%B9%E9%A1%B5%E9%9D%A2%E6%95%B0%E6%8D%AE/", "url": "https://hitoli.com/2023/01/10/Vue%E6%A0%B9%E6%8D%AE%E8%B7%AF%E7%94%B1%E4%BC%A0%E5%8F%82%E4%BF%AE%E6%94%B9%E9%A1%B5%E9%9D%A2%E6%95%B0%E6%8D%AE/", "title": "Vue根据路由传参修改页面数据", "date_published": "2023-01-10T02:19:00.000Z", "content_html": "

# 引言

\n

在开发前端页面时会存在相同的页面展示,只是菜单名称不同、数据类型不同的情况。如果再拷贝一个页面来展示后期就需要维护两个页面,同时也增加了工作量。但是只使用一个页面通过传参来改变数据就方便多了。

\n

# 路由配置

\n
{
    path: '/test/:type/:menuIndex',
    name: 'Test',
    component: _import('xxx/Test.vue')
 }

# 菜单配置

\n
<template>
    <el-menu
      class=\"aside-menu\"
      :default-active=\"menuIndex.toString()\"
      @select=\"handleSelect\"
    >
      <el-menu-item
        index=\"1\"
        class=\"aside-menu-item\"
      >
        <template #title>
          <span>TEST1</span>
          <el-icon :size=\"20\"><TrendCharts /></el-icon>
        </template>
      </el-menu-item>
      <el-menu-item
        index=\"2\"
        class=\"aside-menu-item\"
      >
        <template #title>
          <span>TEST2</span>
          <el-icon :size=\"20\"><Orange /></el-icon>
        </template>
      </el-menu-item>
    </el-menu>
</template>
methods: {
    handleSelect (val) {
      if (val === '1') {
        this.$router.push({ path: '/test/type1/' + val })
      } else if (val === '2') {
        this.$router.push({ path: '/test/type2/' + val })
      }
    }
}

# 页面

\n
created () {
    this.$watch(
      () => this.$route.params,
      (toParams, previousParams) => {
        if (isNotEmpty(toParams.menuIndex)) {
          this.menuIndex = toParams.menuIndex
        }
        if (isNotEmpty(toParams.type)) {
          this.type = toParams.type
        }
        // 根据type查询数据
        ...
      }
    )
    if (isNotEmpty(this.$route.params.menuIndex)) {
      this.menuIndex = this.$route.params.menuIndex
    }
    if (isNotEmpty(this.$route.params.type)) {
      this.type = this.$route.params.type
    }
},
mounted () {
\t// 根据type查询数据
\t...
}
", "tags": [ "工作", "解决问题", "Vue", "Vue" ] }, { "id": "https://hitoli.com/2023/01/10/Highcharts%E7%94%BB%E6%94%B6%E7%9B%8A%E6%A6%82%E8%A7%88/", "url": "https://hitoli.com/2023/01/10/Highcharts%E7%94%BB%E6%94%B6%E7%9B%8A%E6%A6%82%E8%A7%88/", "title": "Highcharts画收益概览", "date_published": "2023-01-10T01:51:00.000Z", "content_html": "

# 引言

\n

项目中需要画一幅收益概览图,研究了一下 Highcharts 的用法。特此收录方便以后再次使用时查阅。
\n\"1ef80bfe8b5ee82aec0e2549e8c68e2c.png\"

\n

# 代码

\n
//x 轴时间集合
var chartXAxisDateTimes = ['2022-01-01 00:00:00', '2022-02-01 00:00:00', '2022-03-01 00:00:00', '2022-04-01 00:00:00', '2022-05-01 00:00:00']
//y 轴数据集合
var chartYAxisDatas = [
          {
            title: '累计收益',
            name: '我的策略累计收益',
            type: 'spline',
            unit: '%',
            valueDecimals: 3,
            height: '28%',
            yAxisIndex: 0, //y 轴分区 index(从上到下,默认从 0 开始)
            data: [{
              x: new Date('2022-01-01 00:00:00').getTime(),
              y: 1,
              color: ''
            },
            {
              x: new Date('2022-02-01 00:00:00').getTime(),
              y: 2,
              color: ''
            },
            {
              x: new Date('2022-03-01 00:00:00').getTime(),
              y: 3,
              color: ''
            },
            {
              x: new Date('2022-04-01 00:00:00').getTime(),
              y: 4,
              color: ''
            },
            {
              x: new Date('2022-05-01 00:00:00').getTime(),
              y: 5,
              color: ''
            }]
          },
          {
            title: '每月盈亏',
            name: '当月盈利',
            type: 'column',
            unit: 'k',
            valueDecimals: 0,
            top: '34%',
            height: '28%',
            yAxisIndex: 1, //y 轴分区 index(从上到下,默认从 0 开始)
            formatter: function () {
              return this.value < 0 ? (-this.value) + 'k' : this.value + 'k'
            },
            data: [{
              x: new Date('2022-01-01 00:00:00').getTime(),
              y: 1,
              color: ''
            },
            {
              x: new Date('2022-02-01 00:00:00').getTime(),
              y: 2,
              color: ''
            },
            {
              x: new Date('2022-03-01 00:00:00').getTime(),
              y: 3,
              color: ''
            },
            {
              x: new Date('2022-04-01 00:00:00').getTime(),
              y: 4,
              color: ''
            },
            {
              x: new Date('2022-05-01 00:00:00').getTime(),
              y: 5,
              color: ''
            }]
          },
          {
            title: '成交记录',
            name: '当月买入',
            type: 'column',
            unit: 'k',
            valueDecimals: 0,
            top: '68%',
            height: '28%',
            yAxisIndex: 2, //y 轴分区 index(从上到下,默认从 0 开始)
            data: [{
              x: new Date('2022-01-01 00:00:00').getTime(),
              y: 1,
              color: 'red'
            },
            {
              x: new Date('2022-02-01 00:00:00').getTime(),
              y: 2,
              color: 'red'
            },
            {
              x: new Date('2022-03-01 00:00:00').getTime(),
              y: 3,
              color: 'red'
            },
            {
              x: new Date('2022-04-01 00:00:00').getTime(),
              y: 4,
              color: 'red'
            },
            {
              x: new Date('2022-05-01 00:00:00').getTime(),
              y: 5,
              color: 'red'
            }]
          },
          {
            title: '成交记录',
            name: '当月卖出',
            type: 'column',
            unit: 'k',
            valueDecimals: 0,
            top: '68%',
            height: '28%',
            yAxisIndex: 2, //y 轴分区 index(从上到下,默认从 0 开始)
            data: [{
              x: new Date('2022-01-01 00:00:00').getTime(),
              y: 1,
              color: 'green'
            },
            {
              x: new Date('2022-02-01 00:00:00').getTime(),
              y: 2,
              color: 'green'
            },
            {
              x: new Date('2022-03-01 00:00:00').getTime(),
              y: 3,
              color: 'green'
            },
            {
              x: new Date('2022-04-01 00:00:00').getTime(),
              y: 4,
              color: 'green'
            },
            {
              x: new Date('2022-05-01 00:00:00').getTime(),
              y: 5,
              color: 'green'
            }]
          }
        ]
\t\t
// 最大回测范围
var plotBandScope = [new Date('2022-02-01 00:00:00').getTime(), new Date('2022-04-01 00:00:00').getTime()]
// 图表配置
var option = {
\tchart: {
\t  height: 600,
\t  type: 'spline' // 指定图表的类型,默认是折线图(line)
\t},
\tplotOptions: {
\t  spline: {
\t\tborderWidth: 0,
\t\tlineWidth: 1,
\t\tstates: {
\t\t  hover: {
\t\t\tlineWidth: 2
\t\t  }
\t\t},
\t\t//pointWidth: 4, // 柱子内宽度容
\t\tdataLabels: {
\t\t  style: {
\t\t\tfontSize: 11
\t\t  },
\t\t  enabled: false
\t\t},
\t\tshowInLegend: true
\t  },
\t  column: {
\t\tborderWidth: 0,
\t\tpointWidth: 4, // 柱子内宽度容
\t\tdataLabels: {
\t\t  style: {
\t\t\tfontSize: 11
\t\t  },
\t\t  enabled: false
\t\t},
\t\tshowInLegend: true,
\t\tgrouping: true
\t  }
\t},
\trangeSelector: {
\t  enabled: false
\t},
\tcredits: {
\t  enabled: false
\t},
\t// legend: {
\t//   enabled: true,
\t//   verticalAlign: 'top'
\t// },
\tnavigator: { // 导航器样式
\t  enabled: true,
\t  height: 20
\t},
\tscrollbar: { // 滚动条样式
\t  barBackgroundColor: 'rgb(209, 218, 237)',
\t  barBorderRadius: 0,
\t  barBorderWidth: 0,
\t  buttonBackgroundColor: 'rgb(242, 242, 242)',
\t  buttonBorderWidth: 0,
\t  buttonBorderRadius: 0,
\t  trackBackgroundColor: 'none',
\t  trackBorderWidth: 1,
\t  trackBorderRadius: 0,
\t  trackBorderColor: '#CCC'
\t},
\txAxis: {
\t  lineWidth: 1,
\t  type: 'datetime',
\t  categories: [],
\t  dateTimeLabelFormats: {
\t\t// millisecond: '%H:%M:%S.%L',
\t\t// second: '%H:%M:%S',
\t\t// minute: '%H:%M',
\t\t// hour: '%m-%d %H:%M',
\t\tday: '%m-%d',
\t\tweek: '%m-%d',
\t\tmonth: '%Y-%m',
\t\tyear: '%Y'
\t  },
\t  gridLineWidth: 1
\t},
\tyAxis: [],
\ttooltip: {
\t  xDateFormat: '%Y-%m-%d %H:%M:%S',
\t  style: {
\t\tfontSize: 16,
\t\tfontFamily: '微软雅黑',
\t\tfontWeight: 'normal',
\t\tcolor: '#666',
\t\tpadding: 10,
\t\tborderWidth: 0,
\t\tbackgroundColor: '#ddd'
\t  },
\t  shared: true,
\t  useHTML: true,
\t  headerFormat: '<small style=\"font-size: 12px\">{point.key}</small><table>', // 标题格式,
\t  pointFormat: '<tr><td><li style=\"color:{series.color};padding:0px\">{series.name}: </li>' +
\t  '<div style=\"float: right;\">{point.y} {series.tooltip.valueDecimals}</div></td></tr>',
\t  footerFormat: '</table>',
\t  shadow: true,
\t  followPointer: true // 跟随鼠标
\t},
\tseries: []
}
// 根据最大回测范围修改图表配置
if (plotBandScope && plotBandScope.length === 2) {
\toption.xAxis.plotBands = [{
\t  from: plotBandScope[0],
\t  to: plotBandScope[1],
\t  color: '#FCFFC5',
\t  label: {
\t\ttext: '最大回测区间',
\t\talign: 'center',
\t\tverticalAlign: 'top',
\t\ty: 14
\t  }
\t}]
}
// 根据 x 轴时间集合修改图表配置
if (chartXAxisDateTimes && chartXAxisDateTimes.length > 0) {
\toption.categories = chartXAxisDateTimes
}
// 根据 y 轴数据集合修改图表配置
if (chartYAxisDatas && chartYAxisDatas.length > 0) {
\tchartYAxisDatas.forEach(function (item, i) {
\t  if (item.type === 'spline' || item.type === 'line') {
\t\toption.yAxis.push({
\t\t  plotLines: [{
\t\t\tcolor: 'black', // 线的颜色,定义为红色
\t\t\tdashStyle: 'solid', // 默认值,这里定义为实线
\t\t\tvalue: 0, // 定义在那个值上显示标示线,这里是在 x 轴上刻度为 3 的值处垂直化一条线
\t\t\twidth: 2 // 标示线的宽度,2px
\t\t  }],
\t\t  tickAmount: 4, // 规定坐标轴上的刻度总数
\t\t  gridLineColor: '#ddd',
\t\t  gridLineDashStyle: 'Solid',
\t\t  labels: { // 坐标轴上刻度的样式及单位
\t\t\talign: 'right',
\t\t\tx: 6,
\t\t\tstyle: {
\t\t\t  color: '#999999',
\t\t\t  fontSize: 12
\t\t\t},
\t\t\tformat: '{value}' + item.unit // 坐标轴上的单位
\t\t  },
\t\t  title: {
\t\t\ttext: item.title,
\t\t\tmargin: 20,
\t\t\tstyle: {
\t\t\t  color: '#999999',
\t\t\t  fontSize: 12,
\t\t\t  align: 'middle' // 坐标轴对齐方式(相对于坐标轴的值) 默认是:middle 居中对齐
\t\t\t}
\t\t  },
\t\t  height: item.height,
\t\t  lineWidth: 0
\t\t})
\t\toption.series.push({
\t\t  name: item.name,
\t\t  data: item.data,
\t\t  type: item.type,
\t\t  color: 'rgb(170, 70, 67)',
\t\t  tooltip: {
\t\t\tvalueSuffix: item.unit, // 数值后缀
\t\t\tvalueDecimals: item.valueDecimals //  提示框数据精度 (保留小数点后 3 位)
\t\t  },
\t\t  yAxis: item.yAxisIndex,
\t\t  showInNavigator: false
\t\t})
\t  } else if (item.type === 'column') {
\t\toption.yAxis.push({
\t\t  type: item.type,
\t\t  tickAmount: 4, // 规定坐标轴上的刻度总数
\t\t  startOnTick: true,
\t\t  reversed: false, //y 轴刻度反转
\t\t  showFirstLabel: false,
\t\t  showLastLabel: true,
\t\t  gridLineColor: '#ddd',
\t\t  gridLineDashStyle: 'Solid',
\t\t  labels: {
\t\t\talign: 'right',
\t\t\tx: 12,
\t\t\tstyle: {
\t\t\t  color: '#999999',
\t\t\t  fontSize: 12
\t\t\t},
\t\t\tformatter: item.formatter,
\t\t\tformat: '{value}' + item.unit // 坐标轴上的单位
\t\t  },
\t\t  title: {
\t\t\ttext: item.title,
\t\t\tmargin: 20,
\t\t\tstyle: {
\t\t\t  color: '#999999',
\t\t\t  fontSize: 12,
\t\t\t  align: 'middle' // 坐标轴对齐方式(相对于坐标轴的值) 默认是:middle 居中对齐
\t\t\t}
\t\t  },
\t\t  top: item.top,
\t\t  height: item.height,
\t\t  offset: 0,
\t\t  lineWidth: 0
\t\t})
\t\toption.series.push({
\t\t  name: item.name,
\t\t  type: item.type,
\t\t  data: item.data,
\t\t  tooltip: {
\t\t\tpointFormatter: function () {
\t\t\t  return '<tr><td><li style=\"color: ' + this.color + ';padding:0px;\"></span> ' + item.name +
\t\t\t\t': </li><div style=\"float: right;\">' + this.y.toFixed(item.valueDecimals) + item.unit + '</div></td></tr>'
\t\t\t}
\t\t  },
\t\t  yAxis: item.yAxisIndex,
\t\t  showInNavigator: false
\t\t})
\t  }
\t})
}
// 画图(container 为 div 的 id)
Highcharts.stockChart('container', option)
", "tags": [ "工作", "解决问题", "Highcharts", "Highcharts" ] }, { "id": "https://hitoli.com/2022/12/05/Win10%E5%BD%BB%E5%BA%95%E5%85%B3%E9%97%ADwsappx%E8%BF%9B%E7%A8%8B/", "url": "https://hitoli.com/2022/12/05/Win10%E5%BD%BB%E5%BA%95%E5%85%B3%E9%97%ADwsappx%E8%BF%9B%E7%A8%8B/", "title": "Win10彻底关闭wsappx进程", "date_published": "2022-12-05T04:23:00.000Z", "content_html": "

# 引言

\n

最近重装了家里一台 mini 电脑,把系统升级成了最新的 win10 系统。但是使用起来却异常卡顿,查看任务管理器发现有个 wsappx 进程占用 cpu 严重。于是百度搜索得知它是微软商店的依赖进程,而我根本就用不上,所以直接禁用。

\n

# 方法一

\n
    \n
  1. 开始菜单点击 “开始 / 应用商店” 菜单项。
  2. \n
  3. 接着就会打开应用商店窗口,在窗口中点击个人头像的图标。
  4. \n
  5. 在弹出的菜单中点击 “设置” 菜单项。
  6. \n
  7. 在打开的应用商店设置窗口中,找到自动更新应用一项。
  8. \n
  9. 点击该项下面的开关,把该项下面的开关设置为关即可。
  10. \n
\n

# 方法二

\n
    \n
  1. win 键 + r,输入 regedit
  2. \n
  3. 计算机 \\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\AppXSvc 将 3 改为 4
    \n\"\"
  4. \n
  5. 计算机 \\HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\ClipSVC 将 3 改为 4
    \n\"\"
  6. \n
  7. 重启电脑
  8. \n
\n", "tags": [ "Windows", "解决问题", "win10", "wsappx" ] }, { "id": "https://hitoli.com/2022/12/02/KLineChart%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E6%A0%87%E7%94%BB%E5%9B%BE/", "url": "https://hitoli.com/2022/12/02/KLineChart%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8C%87%E6%A0%87%E7%94%BB%E5%9B%BE/", "title": "KLineChart实现自定义指标画图", "date_published": "2022-12-02T07:16:00.000Z", "content_html": "

# 引言

\n

本次任务是需要在一个指标图上通过点击标记画出此标记参与计算的数据范围、最高最低值、参考线等等,于是有了以下代码。代码仅供参考,如有错误的地方请指正!
\n\"7fd440be0502d0099427e7c74c4ebf29.jpg\"

\n

# 模版代码

\n
// 箱体指标
const boxDataScope = 300 // 箱体范围
// 黄金线参数
const goldenSectionA = 0.191
const goldenSectionB = 0.382
const goldenSectionC = 0.5
const goldenSectionD = 0.618
const goldenSectionE = 0.809
this.chart.addTechnicalIndicatorTemplate({
\tname: 'custom_box_solid',
    shortName: '箱体',
    precision: 2,
    plots: [ //key 属性的值最好在主图数据范围内,否则 Y 轴的值会跟着变大可能会导致主图变成一条线
      { key: 'max', title: '最高:' },
      { key: 'min', title: '最低:' }
    ],
    calcParams: [boxDataScope, goldenSectionA, goldenSectionB, goldenSectionC, goldenSectionD, goldenSectionE],
    calcTechnicalIndicator: (dataList, { params, plots }) => {
      let allDatas = [] // 所有数据
      let selectedDatas = [] // 选中的数据
      for (let i = 0; i < dataList.length; i++) {
        let kLineData = dataList[i]
        if (new Date(dateConvert(kLineData.timestamp)).getTime() === getGlobalObject('boxId')) {
          const size = params[0]
          // 找出当前数据往前的 size 条数据(包含自己)
          let startData = i - size + 1
          if (startData < 0) {
            startData = 0
          }
          let endData = i + 1
          if (endData > dataList.length) {
            endData = dataList.length
          }
          selectedDatas = dataList.slice(startData, endData)
        }
        allDatas.push({
          timestamp: kLineData.timestamp
        })
      }
      // 找出选中数据中最高最低差价
      let max, min
      selectedDatas.forEach(function (item) {
        let value = item.close - item.close2
        if (!max || value > max) {
          max = value
        }
        if (!min || value < min) {
          min = value
        }
      })
\t  // 返回指标最终数据(未选中的数据用空对象替换)
\t  // 必须返回和 dataList 一样条数的数据,否则 title 不会显示
      return allDatas.map((data, i) => {
        let item = {
        }
        selectedDatas.map((selected, j) => {
          if (data.timestamp === selected.timestamp) {
            item.timestamp = selected.timestamp
            item.max = max
            item.min = min
          }
        })
        return item
      })
    },
    render: ({ ctx, dataSource, viewport, styles, xAxis, yAxis }) => {
      if (dataSource.technicalIndicatorDataList.length <= 0) { // 无指标数据则不处理
        return
      }
\t  // X 轴起始像素
      let x = xAxis.convertToPixel(0)
      // 标记选中数据的起止位置
      let start
      let end = dataSource.technicalIndicatorDataList.length - 1
      dataSource.technicalIndicatorDataList.forEach(function (kLineData, i) {
        if (kLineData.timestamp) {
          if (!start) {
            start = i
          }
          if (i < end && !dataSource.technicalIndicatorDataList[i + 1].timestamp) {
            end = i
          }
          let max = kLineData.max
          let min = kLineData.min
          ctx.fillStyle = '#fff'
          ctx.textBaseline = 'middle'
          ctx.textAlign = 'center'
          // 画箱体
\t\t  // 箱体颜色
\t\t  ctx.strokeStyle = '#DC143C'
\t\t  //y 轴最高点位置
\t\t  let yHigh = yAxis.convertToPixel(max)
\t\t  //y 轴最低点位置
\t\t  let yLow = yAxis.convertToPixel(min)
\t\t  ctx.beginPath()
\t\t  // 画笔移动到数据的 x 轴起始点,y 轴最高点
\t\t  ctx.moveTo(x, yHigh)
          if (i === start) { // 如果是第一条数据则需要画一条竖线
            ctx.lineTo(x, yLow) // 画竖线
            ctx.moveTo(x, yHigh) // 画笔移回
          }
          if (i === end) { // 如果是最后一条数据则需要画一条竖线
            ctx.lineTo(x, yLow) // 画竖线
            ctx.fillText(max, x + viewport.dataSpace, yHigh) // 标识箱体最高点的值
            ctx.moveTo(x, yLow) // 画笔移动到 Y 轴最低点
            ctx.fillText(min, x + viewport.dataSpace, yLow) // 标识箱体最低点的值
          } else { // 画两条横线,一条在 y 轴最高点,一条在 y 轴最低点
            ctx.lineTo(x + viewport.dataSpace, yHigh) //y 轴最高点横线
            ctx.moveTo(x, yLow) // 画笔移动到 y 轴最低点
            ctx.lineTo(x + viewport.dataSpace, yLow) //y 轴最低点横线
          }
          ctx.stroke()
          ctx.closePath()
          // 画黄金线
\t\t  // 黄金线颜色
          ctx.strokeStyle = '#ffffff'
\t\t  // 根据黄金线参数计算黄金线的值
          let goldenSectionLineA = (max - min) * goldenSectionA + min
          let goldenSectionLineB = (max - min) * goldenSectionB + min
          let goldenSectionLineC = (max - min) * goldenSectionC + min
          let goldenSectionLineD = (max - min) * goldenSectionD + min
          let goldenSectionLineE = (max - min) * goldenSectionE + min
\t\t  // 根据黄金线的值获取 Y 轴高度
          let yA = yAxis.convertToPixel(goldenSectionLineA)
          let yB = yAxis.convertToPixel(goldenSectionLineB)
          let yC = yAxis.convertToPixel(goldenSectionLineC)
          let yD = yAxis.convertToPixel(goldenSectionLineD)
          let yE = yAxis.convertToPixel(goldenSectionLineE)
          ctx.beginPath()
\t\t  // 画第一条黄金线
          ctx.moveTo(x, yA)
          ctx.lineTo(x + viewport.barSpace / 2, yA)
          if (i === end) { // 是否最后一条数据,如果是则需要标识黄金线的值
\t\t    // 标识第一条黄金线的值
            ctx.fillText(goldenSectionLineA.toFixed(2), x + viewport.dataSpace, yA)
          }
\t\t  // 画第二条黄金线
          ctx.moveTo(x, yB)
          ctx.lineTo(x + viewport.barSpace / 2, yB)
          if (i === end) {
            ctx.fillText(goldenSectionLineB.toFixed(2), x + viewport.dataSpace, yB)
          }
\t\t  // 画第三条黄金线
          ctx.moveTo(x, yC)
          ctx.lineTo(x + viewport.barSpace / 2, yC)
          if (i === end) {
            ctx.fillText(goldenSectionLineC.toFixed(2), x + viewport.dataSpace, yC)
          }
\t\t  // 画第四条黄金线
          ctx.moveTo(x, yD)
          ctx.lineTo(x + viewport.barSpace / 2, yD)
          if (i === end) {
            ctx.fillText(goldenSectionLineD.toFixed(2), x + viewport.dataSpace, yD)
          }
\t\t  // 画第五条黄金线
          ctx.moveTo(x, yE)
          ctx.lineTo(x + viewport.barSpace / 2, yE)
          if (i === end) {
            ctx.fillText(goldenSectionLineE.toFixed(2), x + viewport.dataSpace, yE)
          }
          ctx.stroke()
          ctx.closePath()
        }
\t\t// 计算 X 轴的下一个位置
        x += viewport.dataSpace
      })
    }
})

# 结语

\n
\n

以上代码只是箱体的指标模版,还需要根据业务逻辑在标记上实现点击事件,然后通过事件动态添加移除箱体指标。

\n
\n", "tags": [ "工作", "解决问题", "KLineChart", "KLineChart", "K线", "自定义指标" ] }, { "id": "https://hitoli.com/2022/11/30/%E5%B0%86nginx%E6%9B%BF%E6%8D%A2%E4%B8%BAtengine/", "url": "https://hitoli.com/2022/11/30/%E5%B0%86nginx%E6%9B%BF%E6%8D%A2%E4%B8%BAtengine/", "title": "将nginx替换为tengine", "date_published": "2022-11-30T09:05:00.000Z", "content_html": "

# 介绍

\n
\n

Tengine 的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的 Web 平台。从 2011 年 12 月开始,Tengine 成为一个开源项目。现在,它由 Tengine 团队开发和维护。Tengine 团队的核心成员来自于淘宝、搜狗等互联网企业。

\n
\n

tengine 简单来说就是淘宝自己基于 nginx 优化的网页引擎,在 nginx 原先基础上继续保持兼容,同时功能扩展,效率提高,可以看到目前淘宝网在这么多人同时使用的情况下依然稳定,我们足以相信 tengine,由于它是 nginx 的一个分生版本,所以几乎完全兼容 nginx,所以我认为 tengine 是搭建 lnmp 环境的不二之选。

\n

# 下载

\n

首先访问 tengine 官方网站,获取最新的下载地址。
\n wget http://tengine.taobao.org/download/tengine-2.3.3.tar.gz

\n

# 获取编译参数

\n

nginx -V

\n

# 编译

\n

./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_gzip_static_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_uwsgi_module --without-http_scgi_module
\n./configure 后面的参数是上一步获取的

\n

# Make

\n

make 或者 make -j 内核数
\n生成的文件在 objs 目录下

\n

# 替换

\n

停止 nginx 服务 service nginx stop
\n 查看 nginx 目录 whereis nginx
\n 备份旧 nginx mv /usr/sbin/nginx /usr/sbin/nginx.old
\n 拷贝 objs 下的 nginx 替换旧 nginx cp ./objs/nginx /usr/sbin/
\n 备份旧 so 文件
\n拷贝 objs 下的 so 文件替换旧的 so 文件 cp ./objs/*.so /usr/lib/nginx/modules/

\n

# 测试

\n

nginx -t 如果打印 test is successful 则表示替换成功。
\n然后执行 service nginx start 进行启动即可

\n", "tags": [ "Linux", "服务", "Nginx", "Nginx", "Tengine" ] }, { "id": "https://hitoli.com/2022/11/30/Nginx%E5%8A%A8%E6%80%81%E8%A7%A3%E6%9E%90%E5%9F%9F%E5%90%8D%E6%96%B9%E6%A1%88/", "url": "https://hitoli.com/2022/11/30/Nginx%E5%8A%A8%E6%80%81%E8%A7%A3%E6%9E%90%E5%9F%9F%E5%90%8D%E6%96%B9%E6%A1%88/", "title": "Nginx动态解析域名方案", "date_published": "2022-11-30T08:35:00.000Z", "content_html": "

# 应用场景:

\n

由于有时候 nginx 代理的时候,第三方域名对应的 ip 可能发生变化,然而没有提前通知,然而如果不配置什么,nginx 又不能智能解析,因此 nginx 动态解析域名就比较重要。

\n

# 使用模块 nginx-upstream-dynamic-servers

\n

该模块在启动 nginx 的时候会对域名进行一次解析,解析完成后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,在 TTL 过期后则会再次发起域名解析请求更新域名所对应的 IP 地址。

\n

需要在 nginx 的配置文件中的 http 配置域内指定使用的 DNS 服务器,在 upstream 中需要进行域名解析的 server 后面添加 resolve 参数。

\n

例:

\n
http {
    resolver    ip;
    upstream test {
        server  www.xxx.com:8080       resolve;
    }
    server {
        listen       8080;
        client_body_buffer_size 10m;
        server_name  localhost;
        location / {
        
                proxy_pass      http://test;
                
        }
        
    }
}

缺点:

\n

1、每次解析域名之后,会从 DNS 服务器获取到改 DNS 的 TTL,在 TTL 期限内不会再次解析,所以如果目标域名发生改变,nginx 不会更新解析,知道 TTL 过期。

\n

2、DNS 服务器在 http 配置域配置全,不能在 location 中细分指定。

\n

# 使用模块 ngx_upstream_jdomain

\n

在 http 配置域中配置 DNS 服务器,在 upstream 中按照这个模块的格式配置,支持设置每隔多少秒进行一次解析(抓包分析过设置 interval 可指定解析间隔),如果解析失败则使用缓存中的上一次解析结果的 IP 地址访问。

\n

例:

\n
http {
    resolver    ip;
    upstream test {
        jdomain  www.xxx.com port=8080 interval=10; #指定域名和端口,每隔 10 秒进行一次解析
    }
    server {
        listen       8080;
        client_body_buffer_size 10m;
        server_name  localhost;
        location / {
                proxy_pass      http://test;
        }
        
    }
}

缺点:DNS 服务器只能在 http 配域中全局配置

\n

# 原生 nginx 使用 set 命令使用变量

\n

将域名置于变量中,在对 proxy_pass 进行转发的时候域名调用变量,可以按照 valid,设置的时间参数间隔地对变量中的域名进行解析。

\n

例:

\n
server {
\tlisten       8080;
\tclient_body_buffer_size 10m;
\tserver_name  localhost;
\tlocation / {
\t\t\tresolver ip valid=3s;
\t\t\tset $five \"www.xxx.com:8080\";
\t\t\tproxy_pass      http://${five};
\t}
\t
}

缺点:upstream 中不支持设置变量,因此后端有多台的时候该方案不可行。

\n

# Tengine

\n

在 upstream 中配置 dynamic_resolve,在 location 配置域中指定 NDS 服务器,按照 valid 设置的时间间隔地进行地址解析。只支持 http 模块的动态域名解析

\n

例:

\n
http {
    upstream test {
        dynamic_resolve fallback=stale fail_timeout=30s;
        server  www.xxx.com:8080;
    }
    server {
        listen       8080;
        location / {
                resolver       ip     valid=3s;
                proxy_pass      http://test;
        }
\t  }
}

缺点:需要将 nginx 的 bin 文件替换为 tengine 的 bin 文件。

\n", "tags": [ "Linux", "服务", "Nginx", "Nginx", "动态域名解析", "Tengine" ] }, { "id": "https://hitoli.com/2022/11/30/Nginx%E9%85%8D%E7%BD%AEstream%E8%B8%A9%E5%9D%91/", "url": "https://hitoli.com/2022/11/30/Nginx%E9%85%8D%E7%BD%AEstream%E8%B8%A9%E5%9D%91/", "title": "Nginx配置stream踩坑", "date_published": "2022-11-30T08:09:00.000Z", "content_html": "

# 引言

\n

stream 模块一般用于 TCP/UDP 数据流的代理和负载均衡,可以通过 stream 模块代理转发 TCP 消息。我是用来转发 mysql、gitee 等连接的,有天 ip 发生了变动导致连接不上。前期试过配置 resolver 114.114.114.114 valid=60s; 来动态解析域名,结果 stream 模块不支持 set 函数,这就导致 ip 变动后必须手动重启或者 reload 一下 nginx 才能正常连接。后面经过搜索发现有人说用 Tengine 替代 nginx 可以实现就试了试,结果发现 Tengine 只能实现 http 下的动态域名解析,至此问题依旧。没办法,我只能通过定时任务加脚本判断 ip 是否变动,如果变动就 reload 一下 nginx。

\n
#!/bin/bash
#使用 crontab -e 命令添加定时任务 */1 * * * * sh /home/xxx/autoReloadNginx.sh
home=\"/home/xxx\" #指定 home 路径,如果使用 `pwd` 则 domainIP.txt 生成在当前用户目录下
domain=xxx.xxx.cn
IP=`ping -4 -c 4 $domain | grep from | tail -n 1 | awk -F ' ' '{print $4}'`
regex=\"\\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\\b\"
if [ `echo $IP | egrep $regex | wc -l` -eq 1 ]; then
        if [ ! -f \"$home/domainIP.txt\" ]; then
                touch $home/domainIP.txt
                echo $IP > $home/domainIP.txt
        else
                oldIP=`cat $home/domainIP.txt`
                if [ \"$IP\" != \"$oldIP\" ]; then
                        nginx -s reload
                        echo $IP > $home/domainIP.txt
                else
                        echo \"The domain name ip has not changed\"
                fi
        fi
else
        echo \"The domain name resolution is incorrect\"
fi
", "tags": [ "Linux", "服务", "Nginx", "Nginx", "Tengine", "stream" ] }, { "id": "https://hitoli.com/2022/11/24/KLineChart%E5%AE%9E%E7%8E%B0%E4%B8%80%E5%B9%85%E5%9B%BE%E4%B8%8A%E7%94%BB%E5%A4%9A%E4%B8%AA%E8%9C%A1%E7%83%9BK%E7%BA%BF/", "url": "https://hitoli.com/2022/11/24/KLineChart%E5%AE%9E%E7%8E%B0%E4%B8%80%E5%B9%85%E5%9B%BE%E4%B8%8A%E7%94%BB%E5%A4%9A%E4%B8%AA%E8%9C%A1%E7%83%9BK%E7%BA%BF/", "title": "KLineChart实现一幅图上画多个蜡烛K线", "date_published": "2022-11-24T00:53:00.000Z", "content_html": "

# 引言

\n

最近接到一个任务是通过 KLineChart✔️8.6.1 实现在一幅图上画两个合约的蜡烛图。研究 api 发现并没有通过配置实现的方法,于是联系作者沟通得知需要自己画图实现。于是有了本篇文章。
\n\"KLineChart.jpg\"

\n

# 添加模版

\n
let shortName = this.constant.periodTypeEnum.getNameByCode(this.klineType) + '    合约2:' + this.currentInstrumentId
this.chart.addTechnicalIndicatorTemplate({
  name: 'custom_candle_solid',
  shortName: shortName,
  precision: 2,
  bar: {
\tupColor: '#EF5350',
\tdownColor: '#26A69A',
\tnoChangeColor: '#888889'
  },
  plots: [
\t{ key: 'open', title: '开: ' },
\t{ key: 'close', title: '收: ' },
\t{ key: 'high', title: '高: ' },
\t{ key: 'low', title: '低: ' }
  ],
  calcTechnicalIndicator: (dataList, { params, plots }) => {
\treturn dataList.map((kLineData, i) => {
\t  return {
\t\tinstrumentId: kLineData.instrumentId,
\t\ttimestamp: getDateTime(new Date(kLineData.timestamp)),
\t\topen: kLineData.open,
\t\tclose: kLineData.close,
\t\thigh: kLineData.high,
\t\tlow: kLineData.low
\t  }
\t})
  },
  render: ({ ctx, dataSource, viewport, styles, xAxis, yAxis }) => {
\t// X 轴起始像素
\tlet x = xAxis.convertToPixel(0)
\tdataSource.technicalIndicatorDataList.forEach(function (kLineData, i) {
\t  let open = kLineData.open
\t  let close = kLineData.close
\t  let high = kLineData.high
\t  let low = kLineData.low
\t  // 给蜡烛柱设置颜色
\t  if (close > open) { // 涨
\t\tctx.strokeStyle = '#EF5350'
\t\tctx.fillStyle = '#EF5350'
\t  } else if (close < open) { // 跌
\t\tctx.strokeStyle = '#26A69A'
\t\tctx.fillStyle = '#26A69A'
\t  } else { // 未变动
\t\tctx.strokeStyle = '#888889'
\t\tctx.fillStyle = '#888889'
\t  }
\t  // 获取开盘价 Y 轴像素
\t  let openY = yAxis.convertToPixel(open)
\t  // 获取收盘价 Y 轴像素
\t  let closeY = yAxis.convertToPixel(close)
\t  // 开、收、高、低的 Y 轴像素
\t  let priceY = [openY, closeY, yAxis.convertToPixel(high), yAxis.convertToPixel(low)]
\t  // 从低到高排序
\t  priceY.sort(function (a, b) {
\t\treturn a - b
\t  })
\t  // 画蜡烛柱上部
\t  ctx.fillRect(x - 0.5, priceY[0], 1, priceY[1] - priceY[0])
\t  // 画蜡烛柱下部
\t  ctx.fillRect(x - 0.5, priceY[2], 1, priceY[3] - priceY[2])
\t  // 蜡烛柱高度
\t  var barHeight = Math.max(1, priceY[2] - priceY[1])
\t  // 画蜡烛柱中部 (viewport.barSpace 蜡烛柱的宽度,随放大缩小操作而变化)
\t  ctx.fillRect(x - (viewport.barSpace / 2), priceY[1], viewport.barSpace, barHeight)
\t  // 下一蜡烛柱 X 轴的起始位置(viewport.dataSpace 蜡烛柱的宽度加蜡烛柱之间的间隔,随放大缩小操作而变化)
\t  x += viewport.dataSpace
\t})
  }
})

# 创建指标

\n
this.chart.createTechnicalIndicator('custom_candle_solid', true, { id: 'paneId10', dragEnabled: true, height: this.height })
", "tags": [ "工作", "解决问题", "KLineChart", "KLineChart", "K线", "蜡烛图" ] }, { "id": "https://hitoli.com/2022/11/21/mysql%E6%95%B0%E6%8D%AE%E5%BA%93auto-increment%E8%87%AA%E5%A2%9E%E9%95%BF%E4%B8%8D%E5%8F%98%E7%9A%84%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95/", "url": "https://hitoli.com/2022/11/21/mysql%E6%95%B0%E6%8D%AE%E5%BA%93auto-increment%E8%87%AA%E5%A2%9E%E9%95%BF%E4%B8%8D%E5%8F%98%E7%9A%84%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95/", "title": "mysql数据库auto_increment自增长不变的处理方法", "date_published": "2022-11-21T06:15:00.000Z", "content_html": "

# 问题描述

\n

今天无意中发现原本能正常增加的 id 突然不变了,查看 sql 发现是取的对应表的自增 id。虽然存到表中的新数据自增 id 变化了,但返回的 id 总是不变。经过查询发现表的自增 id 是存在 information_schema 库中的 tables 表中。tables 表中存储了所有表的对应信息,其中有个 auto_increment 字段存储的就是对应表的下一个自增值。但是 mysql 在新版本中修改了此值的更新规则,老版本中是实时更新,新版本修改为 24 小时更新一次。为了不修改原代码中的逻辑,只能通过修改 mysql 配置使项目正常工作了。

\n

# 解决办法

\n
mysql数据库auto_increment自增长不变的处理方法
修改/etc/mysql/mysql.conf.d/mysqld.cnf
增加一行information_schema_stats_expiry = 0
保存后重启mysql
sudo systemctl restart mysql.service
查询是否生效
show global variables like 'information_schema_stats_expiry';
show session variables like 'information_schema_stats_expiry';
", "tags": [ "工作", "解决问题", "mysql" ] }, { "id": "https://hitoli.com/2022/11/13/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/", "url": "https://hitoli.com/2022/11/13/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7/", "title": "数据库管理工具", "date_published": "2022-11-13T09:31:00.000Z", "content_html": "

# 引言

\n\n

# Navicat

\n
    \n
  1. 下载
  2. \n
  3. 安装一路下一步即可 (注意:安装完成后先不要运行)
    \n\"\"
  4. \n
  5. 注册
    \n\"\"
  6. \n
\n
\n

1、运行注册机
\n 2、修改 Your Name(可不改)
\n3、点击 Patch(此时会提示:navicat.exe - x64 -> Cracked
\n4、运行 navicat
\n5、点击第一个 Generate 获取注册码 (Your Name 上一行)
\n 6、点击 Copy 然后粘贴到 navicat 窗口上(也可能会自动粘贴进去)
\n7、点击 navicat 上的激活按钮,等待一会,失败后会弹出手动激活按钮
\n 8、点击手动激活,窗口上会有一个 request code,把框里的值复制到注册机对应的 request code 框内。
\n9、点击第二个 Generate 获取 Activation Code(激活码),把码复制到 navicat 对应的框内。
\n10、点击激活完成激活。

\n
\n
    \n
  1. 查看注册信息
    \n\"\"
  2. \n
  3. 测试连接
    \n\"\"
  4. \n
  5. 新建库
    \n\"\"
  6. \n
\n

# DBeaver

\n
    \n
  1. 下载
  2. \n
  3. 下载 jdk✔️有 JAVA 环境的不用下载
  4. \n
  5. 修改 dbeaver.ini 配置文件
  6. \n
\n
-vm
D:\\jdk-11.0.11\\bin
-startup
plugins/org.eclipse.equinox.launcher_1.6.300.v20210813-1054.jar
--launcher.library
plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.2.300.v20210828-0802
-vmargs
-XX:+IgnoreUnrecognizedVMOptions
--add-modules=ALL-SYSTEM
-Dosgi.requiredJavaVersion=11
-Xms128m
-Xmx2048m
-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT
-Ddbeaver.distribution.type=zip
-javaagent:F:\\green program\\dbeaver\\dbeaver-agent\\dbeaver-agent.jar
\n

第一二行指定 jdk 地址
\n最后一行指定 dbeaver-agent.jar 注册工具的位置

\n
\n
    \n
  1. 启动
    \n\"\"
  2. \n
  3. 注册成功
    \n\"\"
  4. \n
  5. 测试连接
    \n\"\"
  6. \n
\n", "tags": [ "Windows", "工具", "mysql", "数据库工具" ] }, { "id": "https://hitoli.com/2022/11/09/Vue%E6%8C%89%E7%8E%AF%E5%A2%83%E8%AE%BE%E7%BD%AE%E7%BC%96%E8%AF%91%E9%A1%B9%E7%9B%AE/", "url": "https://hitoli.com/2022/11/09/Vue%E6%8C%89%E7%8E%AF%E5%A2%83%E8%AE%BE%E7%BD%AE%E7%BC%96%E8%AF%91%E9%A1%B9%E7%9B%AE/", "title": "Vue按环境设置编译项目", "date_published": "2022-11-09T01:47:00.000Z", "content_html": "

# 引言

\n\n

# 配置

\n\n

.env.alpha

\n
NODE_ENV = 'production'
VUE_APP_BASE_URL = '/'

.env.prod

\n
NODE_ENV = 'production'
VUE_APP_BASE_URL = '/projectName'
\n
\"scripts\": {
    \"serve\": \"vue-cli-service serve\",
    \"build\": \"vue-cli-service build\",
    \"build-test\": \"vue-cli-service build --mode alpha\",
    \"build-prod\": \"vue-cli-service build --mode prod\",
    \"lint\": \"vue-cli-service lint\"
}
\n
yarn build-test #使用.env.alpha 配置文件中的参数
yarn build-prod #使用.env.prod 配置文件中的参数
yarn build --mode alpha #使用.env.alpha 配置文件中的参数
yarn build --mode prod #使用.env.prod 配置文件中的参数
", "tags": [ "工作", "解决问题", "Vue", "Vue", "项目部署" ] }, { "id": "https://hitoli.com/2022/11/08/Nginx%E9%85%8D%E7%BD%AE-%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/", "url": "https://hitoli.com/2022/11/08/Nginx%E9%85%8D%E7%BD%AE-%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86/", "title": "Nginx配置-反向代理", "date_published": "2022-11-08T02:05:00.000Z", "content_html": "

# 引言

\n\n

# 何为反向代理

\n\n

正向代理:如果把局域网外的 Internet 想象成一个巨大的资源库,则局域网中的客户端要访问 Internet,则需要通过代理服务器来访问,这种代理服务就称为正向代理,下面是正向代理的原理图。
\n\"991a203be1ec82b36e1f326376617d40.png\"
\n 反向代理:看下面原理图,就一目了然。其实客户端对代理是无感知的,因为客户端不需要任何配置就可以访问,我们只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。
\n\"1c87e386a0ce624a3949bda443cf346d.png\"

\n
\n

正向代理和反向代理的区别,一句话就是:如果我们客户端自己用,就是正向代理。如果是在服务器用,用户无感知,就是反向代理。

\n
\n

# Nginx 配置文件

\n\n
# 主进程叫 master,负责管理子进程,子进程叫 worker
# worker_processes 配置项表示开启几个业务进程,一般和 cpu 核数有关
worker_processes  1;
events {
    worker_connections  1024;
}
http {
\t# include 表示可以引入其他文件,此处表示引入 http mime 类型
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
\t# 虚拟主机,可以配置多个
    server {
        listen       80;
        server_name  localhost;
        location / {
        \t# 路径匹配之后,哪个目录下去匹配相应的网页,html 是相对路径
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
\t}
}
\n

去掉注释信息后,可以将 nginx.conf 配置文件分为三部分:

\n
\n
    \n
  1. 全局块
  2. \n
\n
worker_processes  1;
\n
    \n
  1. events 块
  2. \n
\n
events {
\tworker_connections  1024;
}
\n
\n

上述例子就表示每个 work process 支持的最大连接数为 1024。这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。

\n
\n
    \n
  1. http 块
  2. \n
\n
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
    }
}
\n

http 全局块:http 全局块配置的指令包括:文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。

\n

server 块:这块和虚拟主机有密切关系,从用户角度看,虚拟主机和一台独立的硬件主机是完全一样的,该技术的产生是为了节省互联网服务器硬件成本。

\n

location 块:这块的主要作用是:基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称(也可以是 IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓存和应答控制等功能,还有许多第三方模块的配置也在这里进行。

\n
\n

每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。(☆☆☆☆☆)

\n
\n

# 反向代理配置

\n
    \n
  1. location 配置规则
  2. \n
\n
location [ = | ~ | ~* | ^~ | @ ] /uri {
}
=    :用于不含正则表达式的 uri 前,要求请求字符串与 uri 严格匹配,如果匹配成功,就停止继续向下搜索并立即处理该请求。
~    :用于表示 uri 包含正则表达式,并且区分大小写。
~*   :用于表示 uri 包含正则表达式,并且不区分大小写。
^~   :用于不含正则表达式的 uri 前,要求 Nginx 服务器找到标识 uri 和请求字符串匹配度最高的location后,立即使用此 location 处理请求,而不再使用 location 块中的正则 uri 和请求字符串做匹配。
@    : \"@\" 定义一个命名的 location,使用在内部定向时,例如 error_page
/uri  :不带任何修饰符,也表示前缀匹配,但是在正则匹配之后,如果没有正则命中,命中最长的规则
/    :通用匹配,任何未匹配到其它location的请求都会匹配到,相当于switch中的default

uri 没有 “/” 结尾时location /abc/def 可以匹配 /abc/defghi 请求,也可以匹配 /abc/def/ghi 等
\nuri 有 “/” 结尾时location /abc/def/ 不能匹配 /abc/defghi 请求只能匹配 /abc/def/anything 这样的请求☆☆☆☆☆

\n
    \n
  1. proxy_pass 配置规则
  2. \n
\n

url 结尾加上了 /相当于是绝对路径则 Nginx 不会把 location 中匹配的路径部分加入代理 url
\nurl 结尾不加 /Nginx 则会把匹配的路径部分加入代理 uri

\n
情景1:
proxy_pass后有/ 
访问地址:http://localhost:8081/WCP.Service/wcp/modeladapter/download/asc.shtml
最终代理:http://10.194.171.7:13082/modeladapter/download/asc.shtml
location /WCP.Service/wcp/modeladapter/download/ {
\tproxy_pass   http://10.194.171.7:13082/modeladapter/download/;
}
访问地址:http://localhost:8081/model/asc.shtml
最终代理:http://127.0.0.1:8082/model/asc.shtml
location /model/ {
\tproxy_pass   http://127.0.0.1:8082/model/;
}
情景2:
proxy_pass后有/
访问地址:http://localhost:8081/model/asc.shtml
最终代理:http://127.0.0.1:8082/asc.shtml
location /model/ {
\tproxy_pass   http://127.0.0.1:8082/;
}
情景3:
proxy_pass后没有/ 
访问地址:http://localhost:8081/model/asc.shtml
最终代理:http://127.0.0.1:8082/model/asc.shtml
location /model/ {
\tproxy_pass   http://127.0.0.1:8082;
}
情景4
proxy_pass后没有/ 
访问地址:http://localhost:8081/model/asc.shtml
最终代理:http://127.0.0.1:8082/AAAmodel/asc.shtml
location /model/ {
\tproxy_pass   http://127.0.0.1:8082/AAA;
}
情景5
proxy_pass后有/
访问地址:http://localhost:8081/model/asc.shtml
最终代理:http://127.0.0.1:8082/asc.shtml
location /model {
\tproxy_pass   http://127.0.0.1:8082/;
}
情景6
proxy_pass后有/
访问地址:http://localhost:8081/modelBBB/asc.shtml
最终代理:http://127.0.0.1:8082/asc.shtml
location /model {
\tproxy_pass   http://127.0.0.1:8082/;
}

# Nginx 完整配置文件

\n
#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;
    server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
            root   html;
            index  index.html index.htm;
        }
        #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;
        #}
    }
    # 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;
    #    }
    #}
}
", "tags": [ "Linux", "服务", "Nginx", "Nginx", "反向代理" ] }, { "id": "https://hitoli.com/2022/11/04/%E8%AE%B0%E4%B8%80%E6%AC%A1Vue%E9%A1%B9%E7%9B%AE%E7%9A%84%E9%83%A8%E7%BD%B2/", "url": "https://hitoli.com/2022/11/04/%E8%AE%B0%E4%B8%80%E6%AC%A1Vue%E9%A1%B9%E7%9B%AE%E7%9A%84%E9%83%A8%E7%BD%B2/", "title": "记一次Vue项目的部署", "date_published": "2022-11-04T07:21:00.000Z", "content_html": "

# 描述

\n\n

# 过程

\n\n
sudo apt autoremove --purge nodejs
\n
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - && sudo apt-get install -y nodejs
\n
curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
echo \"deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main\" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update && sudo apt-get install yarn
\n
yarn install
\n
yarn build
\n
apt install nginx
\n
server {
        listen 80 default_server;
        listen [::]:80 default_server;
        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;
        root /var/www/html;
        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;
        server_name _;
        location /api {
                proxy_pass http://localhost:8080;
        }
        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                #try_files $uri $uri/ =404;
                alias /opt/codes/dayu-tools-arbitrage-web/dist/;
                index index.html index.htm;
        }

# 其它

\n\n
rm dist -fr
yarn build
", "tags": [ "工作", "解决问题", "Vue", "vue", "NodeJS", "yarn" ] }, { "id": "https://hitoli.com/2022/11/03/%E4%B8%8A%E7%8F%AD%E4%BA%86/", "url": "https://hitoli.com/2022/11/03/%E4%B8%8A%E7%8F%AD%E4%BA%86/", "title": "上班了", "date_published": "2022-11-03T03:25:00.000Z", "content_html": "\n", "tags": [ "生活", "心情", "心情" ] }, { "id": "https://hitoli.com/2022/11/02/2-dev-null%E5%92%8C-dev-null-2-1%E5%92%8C2-1-dev-null%E7%9A%84%E5%8C%BA%E5%88%AB/", "url": "https://hitoli.com/2022/11/02/2-dev-null%E5%92%8C-dev-null-2-1%E5%92%8C2-1-dev-null%E7%9A%84%E5%8C%BA%E5%88%AB/", "title": "2>/dev/null和>/dev/null 2>&1和2>&1>/dev/null的区别", "date_published": "2022-11-02T08:29:00.000Z", "content_html": "

# 区别:

\n
2>/dev/null

意思就是把错误输出到 “黑洞”

\n
>/dev/null 2>&1

默认情况是 1,也就是等同于 1>/dev/null 2>&1。意思就是把标准输出重定向到 “黑洞”,还把错误输出 2 重定向到标准输出 1,也就是标准输出和错误输出都进了 “黑洞”

\n
2>&1 >/dev/null

意思就是把错误输出 2 重定向到标准出书 1,也就是屏幕,标准输出进了 “黑洞”,也就是标准输出进了黑洞,错误输出打印到屏幕

\n

# 解释:

\n
    \n
  1. \n

    文件描述符
    \n Linux 系统预留三个文件描述符:0、1 和 2,他们的意义如下所示:
    \n0—— 标准输入(stdin)
    \n略...
    \n1—— 标准输出(stdout)
    \n在当前目录下,有且只有一个文件名称为 a.txt 的文件,这时我们运行这个命令【ls a.txt】, 就会获得一个标准输出 stdout 的输出结果:a.txt
    \n\"\"
    \n2—— 标准错误(stderr)
    \n在当前目录下,有且只有一个文件名称为 a.txt 的文件,我们运行命令【ls b.txt】,我们就会获得一个标准错误 stderr 的输出结果 “ls:无法访问 b.txt:没有这样的文件或目录”。
    \n\"\"

    \n
  2. \n
  3. \n

    重定向
    \n重定向的符号有两个:> 或 >>,两者的区别是:前者会先清空文件,然后再写入内容,后者会将重定向的内容追加到现有文件的尾部。举例如下:

    \n
  4. \n
\n\n
ls b.txt 2> stderr.txt 1>stdout.txt
\n
ls b.txt > output.txt 2>&1
\n
ls b.txt &> output.txt
ls b.txt >& output.txt #两个表达式效果一样的
    \n
  1. Linux 特殊文件
    \n /dev/null 是一个特殊的设备文件,这个文件接收到任何数据都会被丢弃。因此,null 这个设备通常也被称为位桶(bit bucket)或黑洞。
    \n所以,2>/dev/null 的意思就是将标准错误 stderr 删掉。
  2. \n
\n", "tags": [ "Linux", "Shell", "Shell", "2>&1" ] }, { "id": "https://hitoli.com/2022/11/01/360%E7%8B%AC%E7%AB%8B%E7%89%88%E5%B0%8F%E5%B7%A5%E5%85%B7/", "url": "https://hitoli.com/2022/11/01/360%E7%8B%AC%E7%AB%8B%E7%89%88%E5%B0%8F%E5%B7%A5%E5%85%B7/", "title": "360独立版小工具", "date_published": "2022-11-01T07:20:00.000Z", "content_html": "

# 360 独立版小工具

\n

\"\"
\n360 全家桶众说纷纭但工具箱还是挺实用的,这波小工具可以单独下载使用,有需要的朋友赶紧下载吧!

\n

下载地址

\n

# 部分工具截图

\n

\"\"
\n\"\"
\n\"\"

\n", "tags": [ "Windows", "工具", "360小工具" ] }, { "id": "https://hitoli.com/2022/10/31/%E4%B8%80%E9%94%AE%E5%85%B3%E9%97%ADWindows10-11%E7%B3%BB%E7%BB%9F%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0/", "url": "https://hitoli.com/2022/10/31/%E4%B8%80%E9%94%AE%E5%85%B3%E9%97%ADWindows10-11%E7%B3%BB%E7%BB%9F%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0/", "title": "一键关闭Windows10/11系统自动更新", "date_published": "2022-10-31T07:30:00.000Z", "content_html": "

# 介绍

\n\n

# 下载

\n

win10 / win11 / 本地

\n", "tags": [ "Windows", "工具", "Windows10", "Windows11", "自动更新" ] }, { "id": "https://hitoli.com/2022/10/27/%E6%9E%81%E7%A9%BA%E9%97%B4web%E7%AB%AFhttps%E7%9B%B4%E8%BF%9Enginx%E9%85%8D%E7%BD%AE/", "url": "https://hitoli.com/2022/10/27/%E6%9E%81%E7%A9%BA%E9%97%B4web%E7%AB%AFhttps%E7%9B%B4%E8%BF%9Enginx%E9%85%8D%E7%BD%AE/", "title": "极空间web端https直连nginx配置", "date_published": "2022-10-27T05:34:00.000Z", "content_html": "

# 介绍

\n\n

# 配置

\n
    \n
  1. 需要先把 10000 端口在路由器上做好映射。
  2. \n
  3. 证书生成好并放置到 nginx 上。(证书生成方法不做介绍请自行百度)
  4. \n
  5. http 跳转 https 配置
  6. \n
\n
server {
\t\tif ($scheme = http) {
\t\t\trewrite ^(.*)$ https://$host$1 permanent;
\t\t}
}
    \n
  1. web 端口监听配置
  2. \n
\n
#极空间 - web
server {
\tlisten 10000 ssl http2; #ipv4
\tlisten [::]:10000 ssl http2; #ipv6
\tserver_name xxx.xxx.com; #填写自己的域名,主域名或者子域名
\t#include /etc/nginx/conf.d/ssl/ssl_common.conf;
\tssl_certificate_key /etc/nginx/conf.d/ssl/xxx.key;  #加密证书
\tssl_certificate /etc/nginx/conf.d/ssl/xxx.pem;  #加密证书
\tssl_session_timeout 1d;
\tssl_session_cache shared:MozSSL:10m;
\tssl_session_tickets off;
\tssl_protocols TLSv1.2 TLSv1.3;
\tssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
\tssl_prefer_server_ciphers on;
   #开启 OCSP stapling
\tssl_stapling on;
\tssl_stapling_verify on;
\tclient_max_body_size 128M;
\tadd_header Strict-Transport-Security \"max-age=31536000; includeSubdomains; preload\";
\tproxy_send_timeout 180s; #设置发送超时时间
   proxy_read_timeout 180s; #设置读取超时时间
\t# Prevent Information leaks
\tproxy_hide_header X-Powered-By;
\tproxy_hide_header Server;
\tproxy_hide_header X-AspNetMvc-Version;
\tproxy_hide_header X-AspNet-Version;
\t# http security headers
\tadd_header X-Content-Type-Options nosniff;
\tadd_header Pragma no-cache;
\tadd_header Cache-Control no-store;
\tadd_header X-XSS-Protection \"1; mode=block\";
\tadd_header Referrer-Policy origin-when-cross-origin;
\tadd_header X-Permitted-Cross-Domain-Policies none;
   add_header X-Frame-Options SAMEORIGIN; #允许同域嵌套
\t# Add Security cookie flags
\tproxy_cookie_path ~(.*) \"$1; SameSite=strict; secure; httponly\";
\t# Path to the root of your installation
\tlocation / {
\t\tproxy_intercept_errors on;
\t\tproxy_max_temp_file_size 0;
\t\tproxy_set_header Host $host;
\t\tproxy_set_header X-Real-IP $remote_addr;
\t\tproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
\t\tproxy_set_header X-Forwarded-Proto $scheme;
  
\t\tproxy_pass http://极空间内网ip:5055; #这里设置你自己要跳转的局域网应用;
\t\tproxy_redirect http://域名:5055/home https://域名:10000/home; #极空间在登陆后会跳转到 http 协议的 5055 端口,所以要在此替换为 https 协议的 10000 端口
\t}
\terror_page  500 502 503 504 /500.html;
\terror_page  400 404 /500.html;
\tlocation = /500.html {
\t\troot /usr/share/nginx/html/; #错误 html
\t}
}

# 问题

\n\n", "tags": [ "极空间", "nginx", "极空间", "https", "web" ] } ] }